flower-trellis 0.5.2-beta.0 → 0.5.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.
- package/enhancements/0.6/.agents/skills/trellis-auto-loop/SKILL.md +16 -3
- package/enhancements/0.6/.agents/skills/trellis-check-all/references/document-drift-auto-remediation.md +7 -0
- package/enhancements/0.6/.agents/skills/trellis-check-all/references/reporting-and-disposition.md +2 -2
- package/enhancements/0.6/.agents/skills/trellis-push/SKILL.md +14 -9
- package/enhancements/0.6/.agents/skills/trellis-task-brief/SKILL.md +25 -5
- package/enhancements/0.6/.claude/skills/trellis-auto-loop/SKILL.md +16 -3
- package/enhancements/0.6/.claude/skills/trellis-check-all/references/document-drift-auto-remediation.md +7 -0
- package/enhancements/0.6/.claude/skills/trellis-check-all/references/reporting-and-disposition.md +2 -2
- package/enhancements/0.6/.claude/skills/trellis-push/SKILL.md +14 -9
- package/enhancements/0.6/.claude/skills/trellis-task-brief/SKILL.md +25 -5
- package/enhancements/0.6/overrides/bundles/control-plane-integrity.json +2 -1
- package/enhancements/0.6/overrides/bundles/trellis-meta.json +12 -0
- package/enhancements/0.6/overrides/conflicts.json +558 -3
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/constants-selector.py +6 -0
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/helpers-selector.py +150 -0
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/imports-content.py +4 -0
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/imports-selector.py +8 -0
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/output-content.py +7 -0
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/output-selector.py +13 -0
- package/enhancements/0.6/overrides/patches/scripts/session-context-update-boundary/patch.json +53 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/bundled-overrides-baseline.md +16 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/bundled-overrides-content.md +10 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/customization-principles-baseline.md +7 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/customization-principles-content.md +9 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/file-boundaries-baseline.md +19 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/file-boundaries-content.md +13 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/patch.json +157 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/skill-taxonomy-baseline.md +11 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/skill-taxonomy-content.md +15 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/system-model-baseline.md +9 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/system-model-content.md +13 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/template-hashes-baseline.md +11 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-architecture-and-ownership/template-hashes-content.md +11 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/customization-entry-content.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/customization-entry-selector.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/customization-order-baseline.md +7 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/customization-order-content.md +10 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/patch.json +179 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/platform-edit-route-baseline.md +11 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/platform-edit-route-content.md +11 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/skill-classification-content.md +9 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/skill-classification-selector.md +8 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/skill-edit-route-baseline.md +13 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/skill-edit-route-content.md +13 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/workflow-edit-route-baseline.md +7 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/workflow-edit-route-content.md +8 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/workflow-entry-content.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-customization-routing/workflow-entry-selector.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/current-rules-baseline.md +12 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/current-rules-content.md +11 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/description-content.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/description-selector.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/how-to-use-baseline.md +7 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/how-to-use-content.md +7 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/patch.json +105 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/scope-content.md +10 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-mode-precedence/scope-selector.md +9 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/owner-routing-baseline.md +8 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/owner-routing-content.md +20 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/patch.json +106 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/state-boundary-baseline.md +20 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/state-boundary-content.md +7 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/workflow-change-map-baseline.md +13 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/workflow-change-map-content.md +16 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/workflow-source-content.md +1 -0
- package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/workflow-source-selector.md +1 -0
- package/enhancements/0.6/overrides/patches/workflow/intent-routing/request-triage/content.md +3 -2
- package/enhancements/0.6/overrides/patches/workflow/task-brief-review/phase-1-activate-content.md +2 -2
- package/enhancements/0.6/scripts/auto_loop.py +247 -33
- package/enhancements/0.6/scripts/spec_router.py +486 -25
- package/enhancements/MANIFEST.json +56 -2
- package/package.json +3 -3
- package/src/builtin-plugins/skill-garden/content-adapter.js +29 -6
- package/src/builtin-plugins/skill-garden/provider.js +13 -2
- package/src/lib/patch-conflicts.js +28 -2
- package/src/lib/patch-engine.js +41 -3
- package/src/lib/platform-patch-adapters.js +8 -7
- package/src/lib/trellis-python-command.js +95 -0
package/enhancements/0.6/overrides/patches/skills/trellis-meta/managed-workflow-owners/patch.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 2,
|
|
3
|
+
"id": "trellis-meta-managed-workflow-owners",
|
|
4
|
+
"purpose": "managed_workflow_owners",
|
|
5
|
+
"operations": [
|
|
6
|
+
{
|
|
7
|
+
"id": "trellis-meta-managed-workflow-source",
|
|
8
|
+
"operation": "replace",
|
|
9
|
+
"targetPolicy": "each-existing",
|
|
10
|
+
"targets": [
|
|
11
|
+
{ "kind": "skill", "path": ".agent/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
12
|
+
{ "kind": "skill", "path": ".agents/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
13
|
+
{ "kind": "skill", "path": ".claude/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
14
|
+
{ "kind": "skill", "path": ".codebuddy/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
15
|
+
{ "kind": "skill", "path": ".cursor/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
16
|
+
{ "kind": "skill", "path": ".devin/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
17
|
+
{ "kind": "skill", "path": ".factory/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
18
|
+
{ "kind": "skill", "path": ".github/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
19
|
+
{ "kind": "skill", "path": ".kilocode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
20
|
+
{ "kind": "skill", "path": ".kiro/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
21
|
+
{ "kind": "skill", "path": ".opencode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
22
|
+
{ "kind": "skill", "path": ".pi/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
23
|
+
{ "kind": "skill", "path": ".qoder/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
24
|
+
{ "kind": "skill", "path": ".reasonix/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
25
|
+
{ "kind": "skill", "path": ".trae/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" }
|
|
26
|
+
],
|
|
27
|
+
"selector": { "type": "literal", "source": "workflow-source-selector.md", "expectedMatches": 1 },
|
|
28
|
+
"content": { "source": "workflow-source-content.md" }
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "trellis-meta-managed-owner-routing",
|
|
32
|
+
"operation": "replace",
|
|
33
|
+
"targetPolicy": "each-existing",
|
|
34
|
+
"targets": [
|
|
35
|
+
{ "kind": "skill", "path": ".agent/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
36
|
+
{ "kind": "skill", "path": ".agents/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
37
|
+
{ "kind": "skill", "path": ".claude/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
38
|
+
{ "kind": "skill", "path": ".codebuddy/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
39
|
+
{ "kind": "skill", "path": ".cursor/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
40
|
+
{ "kind": "skill", "path": ".devin/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
41
|
+
{ "kind": "skill", "path": ".factory/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
42
|
+
{ "kind": "skill", "path": ".github/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
43
|
+
{ "kind": "skill", "path": ".kilocode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
44
|
+
{ "kind": "skill", "path": ".kiro/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
45
|
+
{ "kind": "skill", "path": ".opencode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
46
|
+
{ "kind": "skill", "path": ".pi/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
47
|
+
{ "kind": "skill", "path": ".qoder/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
48
|
+
{ "kind": "skill", "path": ".reasonix/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
49
|
+
{ "kind": "skill", "path": ".trae/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" }
|
|
50
|
+
],
|
|
51
|
+
"selector": { "type": "markdown-section", "heading": "## Skill Routing" },
|
|
52
|
+
"baselines": ["owner-routing-baseline.md"],
|
|
53
|
+
"content": { "source": "owner-routing-content.md" }
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"id": "trellis-meta-managed-state-boundary",
|
|
57
|
+
"operation": "replace",
|
|
58
|
+
"targetPolicy": "each-existing",
|
|
59
|
+
"targets": [
|
|
60
|
+
{ "kind": "skill", "path": ".agent/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
61
|
+
{ "kind": "skill", "path": ".agents/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
62
|
+
{ "kind": "skill", "path": ".claude/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
63
|
+
{ "kind": "skill", "path": ".codebuddy/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
64
|
+
{ "kind": "skill", "path": ".cursor/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
65
|
+
{ "kind": "skill", "path": ".devin/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
66
|
+
{ "kind": "skill", "path": ".factory/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
67
|
+
{ "kind": "skill", "path": ".github/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
68
|
+
{ "kind": "skill", "path": ".kilocode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
69
|
+
{ "kind": "skill", "path": ".kiro/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
70
|
+
{ "kind": "skill", "path": ".opencode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
71
|
+
{ "kind": "skill", "path": ".pi/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
72
|
+
{ "kind": "skill", "path": ".qoder/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
73
|
+
{ "kind": "skill", "path": ".reasonix/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
74
|
+
{ "kind": "skill", "path": ".trae/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" }
|
|
75
|
+
],
|
|
76
|
+
"selector": { "type": "markdown-section", "heading": "## Workflow-State Prompt Blocks" },
|
|
77
|
+
"baselines": ["state-boundary-baseline.md"],
|
|
78
|
+
"content": { "source": "state-boundary-content.md" }
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "trellis-meta-managed-workflow-change-map",
|
|
82
|
+
"operation": "replace",
|
|
83
|
+
"targetPolicy": "each-existing",
|
|
84
|
+
"targets": [
|
|
85
|
+
{ "kind": "skill", "path": ".agent/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
86
|
+
{ "kind": "skill", "path": ".agents/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
87
|
+
{ "kind": "skill", "path": ".claude/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
88
|
+
{ "kind": "skill", "path": ".codebuddy/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
89
|
+
{ "kind": "skill", "path": ".cursor/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
90
|
+
{ "kind": "skill", "path": ".devin/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
91
|
+
{ "kind": "skill", "path": ".factory/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
92
|
+
{ "kind": "skill", "path": ".github/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
93
|
+
{ "kind": "skill", "path": ".kilocode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
94
|
+
{ "kind": "skill", "path": ".kiro/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
95
|
+
{ "kind": "skill", "path": ".opencode/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
96
|
+
{ "kind": "skill", "path": ".pi/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
97
|
+
{ "kind": "skill", "path": ".qoder/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
98
|
+
{ "kind": "skill", "path": ".reasonix/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" },
|
|
99
|
+
{ "kind": "skill", "path": ".trae/skills/trellis-meta/references/local-architecture/workflow.md", "missing": "skip" }
|
|
100
|
+
],
|
|
101
|
+
"selector": { "type": "markdown-section", "heading": "## Local Modification Patterns" },
|
|
102
|
+
"baselines": ["workflow-change-map-baseline.md"],
|
|
103
|
+
"content": { "source": "workflow-change-map-content.md" }
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## Workflow-State Prompt Blocks
|
|
2
|
+
|
|
3
|
+
The bottom of `workflow.md` can contain state blocks like this:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
[workflow-state:no_task]
|
|
7
|
+
...
|
|
8
|
+
[/workflow-state:no_task]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Hooks choose the right block based on current task status and inject it into the conversation. Common states include:
|
|
12
|
+
|
|
13
|
+
| State | Meaning |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `no_task` | The current session has no active task. |
|
|
16
|
+
| `planning` | The task is still in requirements, research, or context configuration. |
|
|
17
|
+
| `in_progress` | The task has entered implementation and checking. |
|
|
18
|
+
| `completed` | The task is complete and waiting for wrap-up or archive. |
|
|
19
|
+
|
|
20
|
+
If the user wants to change policies such as "whether to create a task when there is no task," "when task creation may be skipped," or "whether sub-agents are required," edit these state blocks and the routing table above them.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
## Workflow-State Prompt Blocks
|
|
2
|
+
|
|
3
|
+
`workflow.md` may contain paired blocks such as `[workflow-state:no_task]...[/workflow-state:no_task]`. Hooks select the current block and inject it as a one-hop next-action guard.
|
|
4
|
+
|
|
5
|
+
State blocks are not the owner of complete planning, routing, checking, commit, or archive procedures. Keep detailed semantics in the owner skill/helper and keep the state body small enough to identify the immediate gate. If a managed state policy changes, update its Skill-Garden Patch baseline/content and the owning workflow contract together; do not edit only the deployed block.
|
|
6
|
+
|
|
7
|
+
Treat the status names actually present in the local workflow and task runtime as authoritative. Do not copy a fixed state or error matrix into this reference.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Local Modification Patterns
|
|
2
|
+
|
|
3
|
+
Common changes:
|
|
4
|
+
|
|
5
|
+
| Goal | Edit point |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Add a phase | Update the Phase Index, phase body, routing, and state blocks. |
|
|
8
|
+
| Change task creation policy | Update the `no_task` state block and Phase 1 description. |
|
|
9
|
+
| Change the default implementation/check path | Update Phase 2 and skill routing. |
|
|
10
|
+
| Change the wrap-up flow | Update Phase 3 and `finish-work` related descriptions. Note the current split: Phase 3.4 = AI-driven code commits (batched, user-confirmed), Phase 3.5 = `/finish-work` (archive + record session). `/finish-work` refuses to run if the working tree is dirty. |
|
|
11
|
+
| Change platform differences | Update routing descriptions grouped by platform. |
|
|
12
|
+
|
|
13
|
+
After editing, make the AI reread `.trellis/workflow.md`; do not assume the flow from the old conversation is still valid.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## Local Modification Patterns
|
|
2
|
+
|
|
3
|
+
Start from the runtime section, then move to its owner:
|
|
4
|
+
|
|
5
|
+
| Goal | Durable owner route |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| Add or reorder a phase | Workflow Patch/source plus every affected owner handoff |
|
|
8
|
+
| Change task creation or scope policy | Request Triage, task-intent helper, and the managed workflow/state Patch |
|
|
9
|
+
| Change planning activation | `trellis-task-brief` and the task-start guard |
|
|
10
|
+
| Change implement/check execution | `trellis-route`; Check-All remains the unified check entry |
|
|
11
|
+
| Change automatic continuation | `trellis-auto-loop` and its runner action contract |
|
|
12
|
+
| Change spec/commit/archive behavior | `trellis-update-spec`, `trellis-push`, or `trellis-finish-work` respectively |
|
|
13
|
+
| Change recovery after interruption | `trellis-continue` and task-progress state |
|
|
14
|
+
| Change one platform adapter | The owning platform file/Patch while preserving the shared workflow contract |
|
|
15
|
+
|
|
16
|
+
In managed mode, update the source Patch and owner, run the synchronization and compiled-target checks, then reread the final `.trellis/workflow.md`. In native mode, a narrow local edit remains valid when no Plugin ownership claim applies.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
`.trellis/workflow.md` is the runtime semantic contract for the current project. It is sufficient to understand what should happen now, but not always sufficient to locate the durable edit point: Skill-Garden-managed sections must be traced to their Patch and workflow owner before modification.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
`.trellis/workflow.md` is the Trellis workflow source of truth inside the user project. An AI does not need Trellis source code to understand how the current project should move tasks forward; this file is enough.
|
package/enhancements/0.6/overrides/patches/workflow/intent-routing/request-triage/content.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
- Infer `discuss`, `inspect`, `direct_edit`, `task_plan`, or `workflow_action` from the whole current request, scope, risk, side effects, active-task state, and latest explicit switch. Do not classify from one keyword alone.
|
|
2
|
+
- Asking for an opinion, expressing discomfort, rejecting a proposal, or asking how something should change is `discuss` unless the current request also explicitly authorizes a concrete edit. Asking to inspect, explain, verify, or locate a cause is `inspect`; read-only findings do not expand into repair authorization.
|
|
2
3
|
- Repair authorization and permission to skip task planning are separate. If repair scope is unknown, use `inspect` first and reclassify from evidence before editing.
|
|
3
|
-
- `direct_edit` requires known, bounded,
|
|
4
|
-
- Before choosing an approach for non-trivial project work, run `python3 ./.trellis/scripts/spec_router.py "<short query describing the intended action>"` when project-local SOPs or conventions may change the correct action. Build the query from the request, intended commands, affected files or systems, package/layer, and domain terms
|
|
4
|
+
- `direct_edit` requires known, bounded, low-risk, reversible scope, no unresolved design choice, and simple validation. Permission/authentication/data-scope/security, database/migration/release/external effects, or unknown scope remain strong `task_plan` boundaries. Shared contracts, cross-package/layer or multi-entry behavior, configuration, historical regressions, and systematic validation raise the evidence and validation bar; they are risk signals, not automatic `task_plan` outcomes. An exact rollback or mechanically synchronized known change may remain `direct_edit` or `workflow_action` when its behavior, scope, side effects, and validation are already determined.
|
|
5
|
+
- Before choosing an approach for non-trivial project work, run `python3 ./.trellis/scripts/spec_router.py "<short query describing the intended action>"` when project-local SOPs or conventions may change the correct action. Build the query from the request, intended commands, affected files or systems, package/layer, and domain terms. For high-confidence matches, follow `load_strategy`: `full` reads the file, `sections` reads the listed ranges, and `outline` inspects headings before reading relevant ranges; expand beyond that plan only when selected context is insufficient. Apply the same plan to medium-confidence matches only when their path, heading, index description, or reason is clearly relevant.
|
|
5
6
|
- Project Knowledge Discovery applies once per user intent, workflow phase, or decision boundary to Trellis/workflow/config/hooks, CLI behavior, release/publish/deploy/tag, Git history actions, data/migration/rollback, cross-layer design, generated artifacts, and install/sync pipelines. Skip it for pure Q&A, simple read-only inspection, opening local tools, or trivial edits unless project rules may alter the approach.
|
|
6
7
|
- When an active task exists, apply the Active Task Scope Guard before artifact ownership, task routing, or file edits. If new implementation work does not belong to the active task title/brief, stop and choose from the user's intent: create a new task, explicitly include it here and update artifacts first, or proceed untracked without reusing the current task or progress. `task_intent.py` only executes the already-decided create/discard/current-task safety boundary; it does not decide semantic ownership.
|
|
7
8
|
- High-confidence reversible steps proceed without a mechanical task-creation question. Clear complex implementation intent authorizes creating a planning task and entering `trellis-brainstorm`; it never authorizes `task.py start` or implementation.
|
package/enhancements/0.6/overrides/patches/workflow/task-brief-review/phase-1-activate-content.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#### 1.4 Activate task `[required · once]`
|
|
2
2
|
|
|
3
|
-
Before changing task status, load `trellis-task-brief`, refresh `<task>/brief.md`, display the full brief in chat,
|
|
3
|
+
Before changing task status, load `trellis-task-brief`, refresh `<task>/brief.md`, and display the full brief in chat. Unless `trellis-task-brief` validates an explicit preauthorization for the current final Brief, stop the current turn and wait for planning review confirmation. Ordinary implementation or task-creation intent is not confirmation.
|
|
4
4
|
|
|
5
5
|
Lightweight tasks need `prd.md`; complex tasks also need `design.md` and `implement.md`. Sub-agent routes require real entries in both JSONL manifests.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
After a later confirmation, or in the same turn when that explicit preauthorization remains valid, run:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
python3 ./.trellis/scripts/task.py start <task-dir>
|
|
@@ -26,6 +26,7 @@ LEGACY_SCHEMA_VERSION = 1
|
|
|
26
26
|
DEFAULT_PROFILE = "commit-only"
|
|
27
27
|
MAX_FIX_RECHECK = 3
|
|
28
28
|
MAX_PLANNING_REPAIR = 3
|
|
29
|
+
MAX_ARTIFACT_RECONCILE = 3
|
|
29
30
|
DECISION_LOG_LIMIT = 20
|
|
30
31
|
MANIFEST_AUDIT_TAIL_LIMIT = 3
|
|
31
32
|
TASK_PROGRESS_NOTE_LIMIT = 500
|
|
@@ -40,6 +41,7 @@ ALLOWED_TASK_STATUSES = {"planning", "in_progress"}
|
|
|
40
41
|
VALID_IMPLEMENT_ROUTES = {"inline", "subagent"}
|
|
41
42
|
VALID_CHECK_ROUTES = {"check-all-inline", "check-all-subagent"}
|
|
42
43
|
VALID_CHECK_DEPTHS = {"auto", "light", "full"}
|
|
44
|
+
CHECK_ACTIONS = {"run_check_all", "run_recheck"}
|
|
43
45
|
RECOVERABLE_BLOCK_REASONS = {
|
|
44
46
|
"missing-prd",
|
|
45
47
|
"open-questions",
|
|
@@ -936,7 +938,12 @@ def _manifest_payload(state: dict[str, Any], revision: int) -> dict[str, Any]:
|
|
|
936
938
|
}
|
|
937
939
|
|
|
938
940
|
|
|
939
|
-
def _append_manifest_revision(
|
|
941
|
+
def _append_manifest_revision(
|
|
942
|
+
state: dict[str, Any],
|
|
943
|
+
decision_id: str | None = None,
|
|
944
|
+
change_source: str | None = None,
|
|
945
|
+
files: list[str] | None = None,
|
|
946
|
+
) -> dict[str, Any]:
|
|
940
947
|
"""追加并激活一个 run manifest revision。"""
|
|
941
948
|
revisions = state.get("manifest_revisions")
|
|
942
949
|
if not isinstance(revisions, list):
|
|
@@ -948,6 +955,10 @@ def _append_manifest_revision(state: dict[str, Any], decision_id: str | None = N
|
|
|
948
955
|
payload = _manifest_payload(state, next_revision)
|
|
949
956
|
if decision_id:
|
|
950
957
|
payload["decision_id"] = decision_id
|
|
958
|
+
if change_source:
|
|
959
|
+
payload["change_source"] = change_source
|
|
960
|
+
if files:
|
|
961
|
+
payload["files"] = sorted(files)
|
|
951
962
|
encoded = json.dumps(payload, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
|
|
952
963
|
payload["sha256"] = hashlib.sha256(encoded.encode("utf-8")).hexdigest()
|
|
953
964
|
revisions.append(payload)
|
|
@@ -1548,7 +1559,7 @@ def _make_item(repo_root: Path, task_ref: str) -> dict[str, Any]:
|
|
|
1548
1559
|
"blocked_by": [],
|
|
1549
1560
|
"owned_dirty": [],
|
|
1550
1561
|
"decision_count": 0,
|
|
1551
|
-
"attempts": {"fix_recheck": 0},
|
|
1562
|
+
"attempts": {"fix_recheck": 0, "artifact_reconcile": 0},
|
|
1552
1563
|
"last_failure": None,
|
|
1553
1564
|
"last_check": None,
|
|
1554
1565
|
"last_action": None,
|
|
@@ -1608,11 +1619,17 @@ def _action(action: str, item: dict[str, Any], extra: dict[str, Any] | None = No
|
|
|
1608
1619
|
elif action == "run_implement":
|
|
1609
1620
|
base["instruction"] = "进入 Phase 2.1 implement route,并执行实现。"
|
|
1610
1621
|
elif action == "run_check_all":
|
|
1611
|
-
base["instruction"] =
|
|
1622
|
+
base["instruction"] = (
|
|
1623
|
+
"进入 Phase 2.2 check route,按 requested_check_depth 执行统一 Check-All;DOC 修复需精确声明 "
|
|
1624
|
+
"--doc-remediation-file。record 成功后立即 next;返回 retryable 时先在同一 action 自纠。"
|
|
1625
|
+
)
|
|
1612
1626
|
elif action == "run_fix":
|
|
1613
1627
|
base["instruction"] = "根据最近失败摘要修复问题。"
|
|
1614
1628
|
elif action == "run_recheck":
|
|
1615
|
-
base["instruction"] =
|
|
1629
|
+
base["instruction"] = (
|
|
1630
|
+
"修复后重新执行统一 Check-All,不得低于 minimum_check_depth;DOC 修复需精确声明 "
|
|
1631
|
+
"--doc-remediation-file。record 成功后立即 next;返回 retryable 时先在同一 action 自纠。"
|
|
1632
|
+
)
|
|
1616
1633
|
elif action == "run_spec_update":
|
|
1617
1634
|
base["instruction"] = (
|
|
1618
1635
|
"执行 trellis-update-spec 并读取 spec_update_result:no-op/written 时 "
|
|
@@ -1626,7 +1643,11 @@ def _action(action: str, item: dict[str, Any], extra: dict[str, Any] | None = No
|
|
|
1626
1643
|
return base
|
|
1627
1644
|
|
|
1628
1645
|
|
|
1629
|
-
def _remember_action(
|
|
1646
|
+
def _remember_action(
|
|
1647
|
+
item: dict[str, Any],
|
|
1648
|
+
action_data: dict[str, Any],
|
|
1649
|
+
artifact_sha256: dict[str, str] | None = None,
|
|
1650
|
+
) -> dict[str, Any]:
|
|
1630
1651
|
"""记录 runner 已发出的待回写 action。"""
|
|
1631
1652
|
item["last_action"] = {
|
|
1632
1653
|
"action": action_data.get("action"),
|
|
@@ -1636,6 +1657,8 @@ def _remember_action(item: dict[str, Any], action_data: dict[str, Any]) -> dict[
|
|
|
1636
1657
|
for key in ("prd_sha256", "planning_sha256", "handoff_sha256"):
|
|
1637
1658
|
if action_data.get(key):
|
|
1638
1659
|
item["last_action"][key] = action_data[key]
|
|
1660
|
+
if artifact_sha256 is not None:
|
|
1661
|
+
item["last_action"]["artifact_sha256"] = artifact_sha256
|
|
1639
1662
|
item["updated_at"] = _utc_now()
|
|
1640
1663
|
return action_data
|
|
1641
1664
|
|
|
@@ -1963,7 +1986,7 @@ def _next_running_v2(repo_root: Path, state: dict[str, Any]) -> tuple[dict[str,
|
|
|
1963
1986
|
return item, _remember_action(item, _action("run_check_all", item, {
|
|
1964
1987
|
"requested_check_depth": _requested_check_depth(state),
|
|
1965
1988
|
"minimum_check_depth": _minimum_check_depth(item, "run_check_all"),
|
|
1966
|
-
}))
|
|
1989
|
+
}), _task_artifact_hashes(repo_root, item))
|
|
1967
1990
|
if step == "fix":
|
|
1968
1991
|
attempts = int(item.setdefault("attempts", {}).get("fix_recheck", 0))
|
|
1969
1992
|
if attempts > MAX_FIX_RECHECK:
|
|
@@ -1977,7 +2000,7 @@ def _next_running_v2(repo_root: Path, state: dict[str, Any]) -> tuple[dict[str,
|
|
|
1977
2000
|
return item, _remember_action(item, _action("run_recheck", item, {
|
|
1978
2001
|
"requested_check_depth": _requested_check_depth(state),
|
|
1979
2002
|
"minimum_check_depth": _minimum_check_depth(item, "run_recheck"),
|
|
1980
|
-
}))
|
|
2003
|
+
}), _task_artifact_hashes(repo_root, item))
|
|
1981
2004
|
if step == "spec_update":
|
|
1982
2005
|
return item, _remember_action(item, _action("run_spec_update", item))
|
|
1983
2006
|
if step == "commit_only":
|
|
@@ -2294,11 +2317,14 @@ def cmd_retry_blocked(args: argparse.Namespace) -> int:
|
|
|
2294
2317
|
item["status"] = "pending"
|
|
2295
2318
|
item["blocked"] = None
|
|
2296
2319
|
item["last_action"] = None
|
|
2297
|
-
if reason
|
|
2320
|
+
if reason in {"retry-budget-exhausted", "artifact-drift"}:
|
|
2298
2321
|
attempts = item.get("attempts")
|
|
2299
2322
|
if not isinstance(attempts, dict):
|
|
2300
2323
|
attempts = {}
|
|
2301
|
-
|
|
2324
|
+
if reason == "retry-budget-exhausted":
|
|
2325
|
+
attempts["fix_recheck"] = 0
|
|
2326
|
+
else:
|
|
2327
|
+
attempts["artifact_reconcile"] = 0
|
|
2302
2328
|
item["attempts"] = attempts
|
|
2303
2329
|
item["task_status"] = _task_status(repo_root, str(item.get("task")))
|
|
2304
2330
|
item["updated_at"] = _utc_now()
|
|
@@ -3031,6 +3057,175 @@ def _consume_pending_artifact_decision(
|
|
|
3031
3057
|
}
|
|
3032
3058
|
|
|
3033
3059
|
|
|
3060
|
+
def _consume_check_doc_remediation(
|
|
3061
|
+
repo_root: Path,
|
|
3062
|
+
state: dict[str, Any],
|
|
3063
|
+
item: dict[str, Any],
|
|
3064
|
+
action: str,
|
|
3065
|
+
raw_files: list[str],
|
|
3066
|
+
) -> dict[str, Any] | None:
|
|
3067
|
+
"""校验并消费 Check-All 声明的低风险任务文档修复。"""
|
|
3068
|
+
if not raw_files:
|
|
3069
|
+
return None
|
|
3070
|
+
if action not in CHECK_ACTIONS:
|
|
3071
|
+
return {
|
|
3072
|
+
"status": "error",
|
|
3073
|
+
"reason": "doc-remediation-action-not-allowed",
|
|
3074
|
+
"message": "--doc-remediation-file 只允许用于 run_check_all 或 run_recheck。",
|
|
3075
|
+
}
|
|
3076
|
+
if isinstance(item.get("pending_artifact_decision"), dict):
|
|
3077
|
+
return {
|
|
3078
|
+
"status": "error",
|
|
3079
|
+
"reason": "doc-remediation-decision-conflict",
|
|
3080
|
+
"message": "当前 action 同时存在待消费的 decide artifact 授权,不能混用 DOC remediation。",
|
|
3081
|
+
}
|
|
3082
|
+
|
|
3083
|
+
last_action = item.get("last_action")
|
|
3084
|
+
previous = last_action.get("artifact_sha256") if isinstance(last_action, dict) else None
|
|
3085
|
+
if not isinstance(previous, dict):
|
|
3086
|
+
return {
|
|
3087
|
+
"status": "error",
|
|
3088
|
+
"reason": "doc-remediation-baseline-missing",
|
|
3089
|
+
"message": "当前 outstanding check action 没有逐文件 artifact baseline,请重新启动安全流程。",
|
|
3090
|
+
}
|
|
3091
|
+
|
|
3092
|
+
task_dir = _task_dir(repo_root, str(item.get("task") or ""))
|
|
3093
|
+
allowed = {
|
|
3094
|
+
_baseline_key(".", _rel_path(repo_root, task_dir / "implement.md")),
|
|
3095
|
+
_baseline_key(".", _rel_path(repo_root, task_dir / "brief.md")),
|
|
3096
|
+
}
|
|
3097
|
+
declared = {_normalize_record_file(value) for value in raw_files}
|
|
3098
|
+
forbidden = sorted(declared - allowed)
|
|
3099
|
+
if forbidden:
|
|
3100
|
+
return {
|
|
3101
|
+
"status": "error",
|
|
3102
|
+
"reason": "doc-remediation-file-not-allowed",
|
|
3103
|
+
"files": forbidden,
|
|
3104
|
+
"allowed_files": sorted(allowed),
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
current = _task_artifact_hashes(repo_root, item)
|
|
3108
|
+
changed = {
|
|
3109
|
+
key
|
|
3110
|
+
for key in set(previous) | set(current)
|
|
3111
|
+
if previous.get(key) != current.get(key)
|
|
3112
|
+
}
|
|
3113
|
+
if changed != declared:
|
|
3114
|
+
return {
|
|
3115
|
+
"status": "error",
|
|
3116
|
+
"reason": "doc-remediation-files-mismatch",
|
|
3117
|
+
"declared_files": sorted(declared),
|
|
3118
|
+
"changed_files": sorted(changed),
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3121
|
+
planning_hash, handoff_hash = _current_artifact_hashes(repo_root, item)
|
|
3122
|
+
item["planning_sha256"] = planning_hash
|
|
3123
|
+
item["handoff_sha256"] = handoff_hash
|
|
3124
|
+
manifest = _append_manifest_revision(
|
|
3125
|
+
state,
|
|
3126
|
+
change_source="check-doc-remediation",
|
|
3127
|
+
files=sorted(changed),
|
|
3128
|
+
)
|
|
3129
|
+
detail = {
|
|
3130
|
+
"files": sorted(changed),
|
|
3131
|
+
"manifest_revision": manifest["revision"],
|
|
3132
|
+
"manifest_sha256": manifest["sha256"],
|
|
3133
|
+
}
|
|
3134
|
+
_append_item_decision(
|
|
3135
|
+
item,
|
|
3136
|
+
"check_doc_artifacts_rebound",
|
|
3137
|
+
"Check-All 低风险任务文档修复已重新绑定到 manifest",
|
|
3138
|
+
detail,
|
|
3139
|
+
)
|
|
3140
|
+
return detail
|
|
3141
|
+
|
|
3142
|
+
|
|
3143
|
+
def _record_artifact_drift(
|
|
3144
|
+
path: Path,
|
|
3145
|
+
state: dict[str, Any],
|
|
3146
|
+
item: dict[str, Any],
|
|
3147
|
+
action: str,
|
|
3148
|
+
args: argparse.Namespace,
|
|
3149
|
+
summary: str,
|
|
3150
|
+
detail: dict[str, Any],
|
|
3151
|
+
) -> int:
|
|
3152
|
+
"""按 action 风险和预算记录 artifact drift。"""
|
|
3153
|
+
if action not in CHECK_ACTIONS or (
|
|
3154
|
+
args.result == "blocked" and args.failure_type == "artifact-drift"
|
|
3155
|
+
):
|
|
3156
|
+
item["last_action"] = None
|
|
3157
|
+
_block_item(item, "artifact-drift", summary, detail)
|
|
3158
|
+
_write_state(path, state)
|
|
3159
|
+
return _print({
|
|
3160
|
+
"status": "recorded",
|
|
3161
|
+
"run_id": state.get("run_id"),
|
|
3162
|
+
"task": item.get("task"),
|
|
3163
|
+
"item_status": item.get("status"),
|
|
3164
|
+
"current_step": item.get("current_step"),
|
|
3165
|
+
"summary": _format_summary(state, args),
|
|
3166
|
+
})
|
|
3167
|
+
|
|
3168
|
+
attempts = item.setdefault("attempts", {})
|
|
3169
|
+
attempt = int(attempts.get("artifact_reconcile", 0)) + 1
|
|
3170
|
+
attempts["artifact_reconcile"] = attempt
|
|
3171
|
+
item["last_failure"] = {
|
|
3172
|
+
"action": action,
|
|
3173
|
+
"failure_type": "artifact-drift",
|
|
3174
|
+
"summary": summary,
|
|
3175
|
+
"detail": detail,
|
|
3176
|
+
"failed_at": _utc_now(),
|
|
3177
|
+
}
|
|
3178
|
+
if attempt > MAX_ARTIFACT_RECONCILE:
|
|
3179
|
+
item["last_action"] = None
|
|
3180
|
+
_block_item(
|
|
3181
|
+
item,
|
|
3182
|
+
"artifact-drift",
|
|
3183
|
+
"Check action artifact drift 连续自纠超过 3 次",
|
|
3184
|
+
{**detail, "attempt": attempt, "max_attempts": MAX_ARTIFACT_RECONCILE},
|
|
3185
|
+
)
|
|
3186
|
+
_write_state(path, state)
|
|
3187
|
+
return _print({
|
|
3188
|
+
"status": "recorded",
|
|
3189
|
+
"run_id": state.get("run_id"),
|
|
3190
|
+
"task": item.get("task"),
|
|
3191
|
+
"item_status": item.get("status"),
|
|
3192
|
+
"current_step": item.get("current_step"),
|
|
3193
|
+
"summary": _format_summary(state, args),
|
|
3194
|
+
})
|
|
3195
|
+
|
|
3196
|
+
item["updated_at"] = _utc_now()
|
|
3197
|
+
_append_item_decision(
|
|
3198
|
+
item,
|
|
3199
|
+
"warning",
|
|
3200
|
+
summary,
|
|
3201
|
+
{
|
|
3202
|
+
"action": action,
|
|
3203
|
+
"failure_type": "artifact-drift",
|
|
3204
|
+
"attempt": attempt,
|
|
3205
|
+
"max_attempts": MAX_ARTIFACT_RECONCILE,
|
|
3206
|
+
"detail": detail,
|
|
3207
|
+
},
|
|
3208
|
+
)
|
|
3209
|
+
_write_state(path, state)
|
|
3210
|
+
return _print({
|
|
3211
|
+
"status": "retryable",
|
|
3212
|
+
"reason": "artifact-drift",
|
|
3213
|
+
"run_id": state.get("run_id"),
|
|
3214
|
+
"task": item.get("task"),
|
|
3215
|
+
"item_status": item.get("status"),
|
|
3216
|
+
"current_step": item.get("current_step"),
|
|
3217
|
+
"attempt": attempt,
|
|
3218
|
+
"max_attempts": MAX_ARTIFACT_RECONCILE,
|
|
3219
|
+
"outstanding_action": action,
|
|
3220
|
+
"detail": detail,
|
|
3221
|
+
"instruction": (
|
|
3222
|
+
"不要运行 next;撤回本 action 的误改后重录,或为合法 implement.md/brief.md 修复补充 "
|
|
3223
|
+
"--doc-remediation-file。无法安全归因时用 blocked + artifact-drift 重录。"
|
|
3224
|
+
),
|
|
3225
|
+
"summary": _format_summary(state, args),
|
|
3226
|
+
})
|
|
3227
|
+
|
|
3228
|
+
|
|
3034
3229
|
def cmd_record(args: argparse.Namespace) -> int:
|
|
3035
3230
|
"""记录 agent 执行结果。"""
|
|
3036
3231
|
repo_root = _repo_root()
|
|
@@ -3144,24 +3339,47 @@ def cmd_record(args: argparse.Namespace) -> int:
|
|
|
3144
3339
|
"current_step": item.get("current_step"),
|
|
3145
3340
|
"summary": _format_summary(state, args),
|
|
3146
3341
|
})
|
|
3342
|
+
doc_rebind = _consume_check_doc_remediation(
|
|
3343
|
+
repo_root,
|
|
3344
|
+
state,
|
|
3345
|
+
item,
|
|
3346
|
+
action,
|
|
3347
|
+
args.doc_remediation_file,
|
|
3348
|
+
)
|
|
3349
|
+
if isinstance(doc_rebind, dict) and doc_rebind.get("status") == "error":
|
|
3350
|
+
doc_rebind.update({"task": item.get("task"), "action": action})
|
|
3351
|
+
return _print(doc_rebind)
|
|
3147
3352
|
artifact_rebind = _consume_pending_artifact_decision(repo_root, state, item)
|
|
3148
3353
|
if isinstance(artifact_rebind, dict) and artifact_rebind.get("unauthorized"):
|
|
3149
|
-
|
|
3150
|
-
|
|
3354
|
+
return _record_artifact_drift(
|
|
3355
|
+
path,
|
|
3356
|
+
state,
|
|
3151
3357
|
item,
|
|
3152
|
-
|
|
3358
|
+
action,
|
|
3359
|
+
args,
|
|
3153
3360
|
"planning/handoff artifacts 的变化未被当前 AI 决策文件范围授权",
|
|
3154
3361
|
artifact_rebind,
|
|
3155
3362
|
)
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3363
|
+
if action in CHECK_ACTIONS and doc_rebind is None and artifact_rebind is None:
|
|
3364
|
+
last_action = item.get("last_action")
|
|
3365
|
+
previous = last_action.get("artifact_sha256") if isinstance(last_action, dict) else None
|
|
3366
|
+
if isinstance(previous, dict):
|
|
3367
|
+
current = _task_artifact_hashes(repo_root, item)
|
|
3368
|
+
changed = sorted(
|
|
3369
|
+
key
|
|
3370
|
+
for key in set(previous) | set(current)
|
|
3371
|
+
if previous.get(key) != current.get(key)
|
|
3372
|
+
)
|
|
3373
|
+
if changed:
|
|
3374
|
+
return _record_artifact_drift(
|
|
3375
|
+
path,
|
|
3376
|
+
state,
|
|
3377
|
+
item,
|
|
3378
|
+
action,
|
|
3379
|
+
args,
|
|
3380
|
+
"Check action 发出后 planning/handoff 文件发生未声明变化",
|
|
3381
|
+
{"changed_files": changed},
|
|
3382
|
+
)
|
|
3165
3383
|
if item.get("planning_sha256"):
|
|
3166
3384
|
try:
|
|
3167
3385
|
planning_hash, handoff_hash = _current_artifact_hashes(repo_root, item)
|
|
@@ -3179,22 +3397,15 @@ def cmd_record(args: argparse.Namespace) -> int:
|
|
|
3179
3397
|
planning_hash != item.get("planning_sha256")
|
|
3180
3398
|
or handoff_hash != item.get("handoff_sha256")
|
|
3181
3399
|
):
|
|
3182
|
-
|
|
3183
|
-
|
|
3400
|
+
return _record_artifact_drift(
|
|
3401
|
+
path,
|
|
3402
|
+
state,
|
|
3184
3403
|
item,
|
|
3185
|
-
|
|
3404
|
+
action,
|
|
3405
|
+
args,
|
|
3186
3406
|
"action 发出后 planning/handoff artifacts 发生未授权变化",
|
|
3187
3407
|
drift_detail,
|
|
3188
3408
|
)
|
|
3189
|
-
_write_state(path, state)
|
|
3190
|
-
return _print({
|
|
3191
|
-
"status": "recorded",
|
|
3192
|
-
"run_id": state.get("run_id"),
|
|
3193
|
-
"task": item.get("task"),
|
|
3194
|
-
"item_status": item.get("status"),
|
|
3195
|
-
"current_step": item.get("current_step"),
|
|
3196
|
-
"summary": _format_summary(state, args),
|
|
3197
|
-
})
|
|
3198
3409
|
conflicts = _protected_path_conflicts(state, args.files)
|
|
3199
3410
|
if conflicts:
|
|
3200
3411
|
item["last_action"] = None
|
|
@@ -3220,6 +3431,8 @@ def cmd_record(args: argparse.Namespace) -> int:
|
|
|
3220
3431
|
return _print(check_error)
|
|
3221
3432
|
|
|
3222
3433
|
_record_check_result(state, item, action, args)
|
|
3434
|
+
if action in CHECK_ACTIONS:
|
|
3435
|
+
item.setdefault("attempts", {})["artifact_reconcile"] = 0
|
|
3223
3436
|
item["last_action"] = None
|
|
3224
3437
|
if args.result == "ok":
|
|
3225
3438
|
_advance_after_ok(item, action, args)
|
|
@@ -3411,6 +3624,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
3411
3624
|
record.add_argument("--failure-type")
|
|
3412
3625
|
record.add_argument("--summary")
|
|
3413
3626
|
record.add_argument("--files", nargs="*")
|
|
3627
|
+
record.add_argument("--doc-remediation-file", action="append", default=[])
|
|
3414
3628
|
record.add_argument("--retained-files", nargs="*")
|
|
3415
3629
|
record.add_argument("--commit")
|
|
3416
3630
|
record.add_argument("--commit-message")
|