@mindfoldhq/trellis 0.1.9 → 0.2.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/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -6
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +684 -42
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/opencode.js +1 -1
- package/dist/configurators/opencode.js.map +1 -1
- package/dist/configurators/workflow.d.ts +4 -3
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +23 -20
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/constants/paths.d.ts +29 -30
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +32 -35
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/index.d.ts +35 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +124 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/manifests/0.1.9.json +30 -0
- package/dist/migrations/manifests/0.2.0.json +43 -0
- package/dist/templates/claude/agents/check.md +3 -3
- package/dist/templates/claude/agents/debug.md +1 -1
- package/dist/templates/claude/agents/dispatch.md +12 -12
- package/dist/templates/claude/agents/implement.md +6 -6
- package/dist/templates/claude/agents/plan.md +37 -37
- package/dist/templates/claude/agents/research.md +1 -1
- package/dist/templates/claude/commands/before-backend-dev.md +5 -5
- package/dist/templates/claude/commands/before-frontend-dev.md +5 -5
- package/dist/templates/claude/commands/break-loop.md +2 -2
- package/dist/templates/claude/commands/check-backend.md +6 -6
- package/dist/templates/claude/commands/check-cross-layer.md +5 -5
- package/dist/templates/claude/commands/check-frontend.md +6 -6
- package/dist/templates/claude/commands/create-command.md +3 -3
- package/dist/templates/claude/commands/finish-work.md +6 -6
- package/dist/templates/claude/commands/integrate-skill.md +11 -11
- package/dist/templates/claude/commands/{onboard-developer.md → onboard.md} +31 -28
- package/dist/templates/claude/commands/parallel.md +17 -17
- package/dist/templates/claude/commands/{record-agent-flow.md → record-session.md} +7 -7
- package/dist/templates/claude/commands/start.md +36 -36
- package/dist/templates/claude/hooks/inject-subagent-context.py +77 -76
- package/dist/templates/claude/hooks/ralph-loop.py +18 -18
- package/dist/templates/claude/hooks/session-start.py +4 -4
- package/dist/templates/cursor/commands/before-backend-dev.md +5 -5
- package/dist/templates/cursor/commands/before-frontend-dev.md +5 -5
- package/dist/templates/cursor/commands/break-loop.md +2 -2
- package/dist/templates/cursor/commands/check-backend.md +6 -6
- package/dist/templates/cursor/commands/check-cross-layer.md +5 -5
- package/dist/templates/cursor/commands/check-frontend.md +6 -6
- package/dist/templates/cursor/commands/create-command.md +3 -3
- package/dist/templates/cursor/commands/finish-work.md +6 -6
- package/dist/templates/cursor/commands/integrate-skill.md +11 -11
- package/dist/templates/cursor/commands/{onboard-developer.md → onboard.md} +31 -28
- package/dist/templates/cursor/commands/{record-agent-flow.md → record-session.md} +7 -7
- package/dist/templates/cursor/commands/start.md +25 -25
- package/dist/templates/extract.d.ts +2 -2
- package/dist/templates/extract.js +2 -2
- package/dist/templates/markdown/agents.md +2 -2
- package/dist/templates/markdown/gitignore.txt +2 -2
- package/dist/templates/markdown/index.d.ts +1 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +4 -2
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/{agent-traces-index.md → workspace-index.md} +14 -14
- package/dist/templates/trellis/index.d.ts +7 -1
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +14 -2
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add-session.sh +26 -26
- package/dist/templates/trellis/scripts/common/developer.sh +20 -21
- package/dist/templates/trellis/scripts/common/git-context.sh +90 -115
- package/dist/templates/trellis/scripts/common/paths.sh +53 -63
- package/dist/templates/trellis/scripts/common/phase.sh +40 -40
- package/dist/templates/trellis/scripts/common/registry.sh +13 -13
- package/dist/templates/trellis/scripts/common/task-queue.sh +142 -0
- package/dist/templates/trellis/scripts/common/task-utils.sh +151 -0
- package/dist/templates/trellis/scripts/common/worktree.sh +3 -3
- package/dist/templates/trellis/scripts/create-bootstrap.sh +43 -42
- package/dist/templates/trellis/scripts/init-developer.sh +1 -1
- package/dist/templates/trellis/scripts/multi-agent/cleanup.sh +33 -33
- package/dist/templates/trellis/scripts/multi-agent/create-pr.sh +30 -30
- package/dist/templates/trellis/scripts/multi-agent/plan.sh +28 -28
- package/dist/templates/trellis/scripts/multi-agent/start.sh +56 -56
- package/dist/templates/trellis/scripts/multi-agent/status.sh +59 -59
- package/dist/templates/trellis/scripts/{feature.sh → task.sh} +235 -185
- package/dist/templates/trellis/workflow.md +71 -74
- package/dist/types/migration.d.ts +74 -0
- package/dist/types/migration.d.ts.map +1 -0
- package/dist/types/migration.js +8 -0
- package/dist/types/migration.js.map +1 -0
- package/dist/utils/template-hash.d.ts +78 -0
- package/dist/utils/template-hash.d.ts.map +1 -0
- package/dist/utils/template-hash.js +234 -0
- package/dist/utils/template-hash.js.map +1 -0
- package/package.json +1 -1
- package/dist/templates/trellis/scripts/common/backlog.sh +0 -220
- package/dist/templates/trellis/scripts/common/feature-utils.sh +0 -194
- /package/dist/templates/trellis/{backlog → tasks}/.gitkeep +0 -0
|
@@ -35,14 +35,14 @@ cat .trellis/workflow.md
|
|
|
35
35
|
./.trellis/scripts/get-context.sh
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
This shows: developer identity, git status, current
|
|
38
|
+
This shows: developer identity, git status, current task (if any), active tasks.
|
|
39
39
|
|
|
40
40
|
### Step 3: Read Guidelines Index
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
cat .trellis/
|
|
44
|
-
cat .trellis/
|
|
45
|
-
cat .trellis/
|
|
43
|
+
cat .trellis/spec/frontend/index.md # Frontend guidelines
|
|
44
|
+
cat .trellis/spec/backend/index.md # Backend guidelines
|
|
45
|
+
cat .trellis/spec/guides/index.md # Thinking guides
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
### Step 4: Report and Ask
|
|
@@ -59,13 +59,13 @@ When user describes a task, classify it:
|
|
|
59
59
|
|------|----------|----------|
|
|
60
60
|
| **Question** | User asks about code, architecture, or how something works | Answer directly |
|
|
61
61
|
| **Trivial Fix** | Typo fix, comment update, single-line change, < 5 minutes | Direct Edit |
|
|
62
|
-
| **Development Task** | Any code change that: modifies logic, adds features, fixes bugs, touches multiple files | **
|
|
62
|
+
| **Development Task** | Any code change that: modifies logic, adds features, fixes bugs, touches multiple files | **Task Workflow** |
|
|
63
63
|
|
|
64
64
|
### Decision Rule
|
|
65
65
|
|
|
66
|
-
> **If in doubt, use
|
|
66
|
+
> **If in doubt, use Task Workflow.**
|
|
67
67
|
>
|
|
68
|
-
>
|
|
68
|
+
> Task Workflow ensures specs are injected to agents, resulting in higher quality code.
|
|
69
69
|
> The overhead is minimal, but the benefit is significant.
|
|
70
70
|
|
|
71
71
|
---
|
|
@@ -79,7 +79,7 @@ For questions or trivial fixes, work directly:
|
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
82
|
-
##
|
|
82
|
+
## Task Workflow (Development Tasks)
|
|
83
83
|
|
|
84
84
|
**Why this workflow?**
|
|
85
85
|
- Research Agent analyzes what specs are needed
|
|
@@ -110,7 +110,7 @@ Task(
|
|
|
110
110
|
Type: <frontend/backend/fullstack>
|
|
111
111
|
|
|
112
112
|
Please find:
|
|
113
|
-
1. Relevant spec files in .trellis/
|
|
113
|
+
1. Relevant spec files in .trellis/spec/
|
|
114
114
|
2. Existing code patterns to follow (find 2-3 examples)
|
|
115
115
|
3. Files that will likely need modification
|
|
116
116
|
|
|
@@ -124,18 +124,18 @@ Task(
|
|
|
124
124
|
## Files to Modify
|
|
125
125
|
- <path>: <what change>
|
|
126
126
|
|
|
127
|
-
## Suggested
|
|
127
|
+
## Suggested Task Name
|
|
128
128
|
- <short-slug-name>",
|
|
129
129
|
model: "opus"
|
|
130
130
|
)
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
### Step 3: Create
|
|
133
|
+
### Step 3: Create Task Directory `[AI]`
|
|
134
134
|
|
|
135
135
|
Based on research results:
|
|
136
136
|
|
|
137
137
|
```bash
|
|
138
|
-
|
|
138
|
+
TASK_DIR=$(./.trellis/scripts/task.sh create "<title from research>" --slug <suggested-slug>)
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
### Step 4: Configure Context `[AI]`
|
|
@@ -143,7 +143,7 @@ FEATURE_DIR=$(./.trellis/scripts/feature.sh create "<title from research>" --slu
|
|
|
143
143
|
Initialize default context:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
./.trellis/scripts/
|
|
146
|
+
./.trellis/scripts/task.sh init-context "$TASK_DIR" <type>
|
|
147
147
|
# type: backend | frontend | fullstack
|
|
148
148
|
```
|
|
149
149
|
|
|
@@ -151,16 +151,16 @@ Add specs found by Research Agent:
|
|
|
151
151
|
|
|
152
152
|
```bash
|
|
153
153
|
# For each relevant spec and code pattern:
|
|
154
|
-
./.trellis/scripts/
|
|
155
|
-
./.trellis/scripts/
|
|
154
|
+
./.trellis/scripts/task.sh add-context "$TASK_DIR" implement "<path>" "<reason>"
|
|
155
|
+
./.trellis/scripts/task.sh add-context "$TASK_DIR" check "<path>" "<reason>"
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
### Step 5: Write Requirements `[AI]`
|
|
159
159
|
|
|
160
|
-
Create `prd.md` in the
|
|
160
|
+
Create `prd.md` in the task directory with:
|
|
161
161
|
|
|
162
162
|
```markdown
|
|
163
|
-
# <
|
|
163
|
+
# <Task Title>
|
|
164
164
|
|
|
165
165
|
## Goal
|
|
166
166
|
<What we're trying to achieve>
|
|
@@ -177,13 +177,13 @@ Create `prd.md` in the feature directory with:
|
|
|
177
177
|
<Any technical decisions or constraints>
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
### Step 6: Activate
|
|
180
|
+
### Step 6: Activate Task `[AI]`
|
|
181
181
|
|
|
182
182
|
```bash
|
|
183
|
-
./.trellis/scripts/
|
|
183
|
+
./.trellis/scripts/task.sh start "$TASK_DIR"
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
-
This sets `.current-
|
|
186
|
+
This sets `.current-task` so hooks can inject context.
|
|
187
187
|
|
|
188
188
|
### Step 7: Implement `[AI]`
|
|
189
189
|
|
|
@@ -192,7 +192,7 @@ Call Implement Agent (specs are auto-injected by hook):
|
|
|
192
192
|
```
|
|
193
193
|
Task(
|
|
194
194
|
subagent_type: "implement",
|
|
195
|
-
prompt: "Implement the
|
|
195
|
+
prompt: "Implement the task described in prd.md.
|
|
196
196
|
|
|
197
197
|
Follow all specs that have been injected into your context.
|
|
198
198
|
Run lint and typecheck before finishing.",
|
|
@@ -222,17 +222,17 @@ Task(
|
|
|
222
222
|
3. Remind user to:
|
|
223
223
|
- Test the changes
|
|
224
224
|
- Commit when ready
|
|
225
|
-
- Run `/record-
|
|
225
|
+
- Run `/record-session` to record this session
|
|
226
226
|
|
|
227
227
|
---
|
|
228
228
|
|
|
229
|
-
## Continuing Existing
|
|
229
|
+
## Continuing Existing Task
|
|
230
230
|
|
|
231
|
-
If `get-context.sh` shows a current
|
|
231
|
+
If `get-context.sh` shows a current task:
|
|
232
232
|
|
|
233
|
-
1. Read the
|
|
234
|
-
2. Check `
|
|
235
|
-
3. Ask user: "Continue working on <
|
|
233
|
+
1. Read the task's `prd.md` to understand the goal
|
|
234
|
+
2. Check `task.json` for current status and phase
|
|
235
|
+
3. Ask user: "Continue working on <task-name>?"
|
|
236
236
|
|
|
237
237
|
If yes, resume from the appropriate step (usually Step 7 or 8).
|
|
238
238
|
|
|
@@ -245,21 +245,21 @@ If yes, resume from the appropriate step (usually Step 7 or 8).
|
|
|
245
245
|
| Command | When to Use |
|
|
246
246
|
|---------|-------------|
|
|
247
247
|
| `/start` | Begin a session (this command) |
|
|
248
|
-
| `/parallel` | Complex
|
|
248
|
+
| `/parallel` | Complex tasks needing isolated worktree |
|
|
249
249
|
| `/finish-work` | Before committing changes |
|
|
250
|
-
| `/record-
|
|
250
|
+
| `/record-session` | After completing a task |
|
|
251
251
|
|
|
252
252
|
### AI Scripts `[AI]`
|
|
253
253
|
|
|
254
254
|
| Script | Purpose |
|
|
255
255
|
|--------|---------|
|
|
256
256
|
| `get-context.sh` | Get session context |
|
|
257
|
-
| `
|
|
258
|
-
| `
|
|
259
|
-
| `
|
|
260
|
-
| `
|
|
261
|
-
| `
|
|
262
|
-
| `
|
|
257
|
+
| `task.sh create` | Create task directory |
|
|
258
|
+
| `task.sh init-context` | Initialize jsonl files |
|
|
259
|
+
| `task.sh add-context` | Add spec to jsonl |
|
|
260
|
+
| `task.sh start` | Set current task |
|
|
261
|
+
| `task.sh finish` | Clear current task |
|
|
262
|
+
| `task.sh archive` | Archive completed task |
|
|
263
263
|
|
|
264
264
|
### Sub Agents `[AI]`
|
|
265
265
|
|
|
@@ -276,5 +276,5 @@ If yes, resume from the appropriate step (usually Step 7 or 8).
|
|
|
276
276
|
|
|
277
277
|
> **Specs are injected, not remembered.**
|
|
278
278
|
>
|
|
279
|
-
> The
|
|
279
|
+
> The Task Workflow ensures agents receive relevant specs automatically.
|
|
280
280
|
> This is more reliable than hoping the AI "remembers" conventions.
|
|
@@ -10,7 +10,7 @@ Core Design Philosophy:
|
|
|
10
10
|
|
|
11
11
|
Trigger: PreToolUse (before Task tool call)
|
|
12
12
|
|
|
13
|
-
Context Source: .trellis/.current-
|
|
13
|
+
Context Source: .trellis/.current-task points to task directory
|
|
14
14
|
- implement.jsonl - Implement agent dedicated context
|
|
15
15
|
- check.jsonl - Check agent dedicated context
|
|
16
16
|
- debug.jsonl - Debug agent dedicated context
|
|
@@ -31,10 +31,11 @@ from pathlib import Path
|
|
|
31
31
|
# =============================================================================
|
|
32
32
|
|
|
33
33
|
DIR_WORKFLOW = ".trellis"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
DIR_WORKSPACE = "workspace"
|
|
35
|
+
DIR_TASKS = "tasks"
|
|
36
|
+
DIR_SPEC = "spec"
|
|
37
|
+
FILE_CURRENT_TASK = ".current-task"
|
|
38
|
+
FILE_TASK_JSON = "task.json"
|
|
38
39
|
|
|
39
40
|
# Agents that don't update phase (can be called at any time)
|
|
40
41
|
AGENTS_NO_PHASE_UPDATE = {"debug", "research"}
|
|
@@ -48,8 +49,8 @@ AGENT_CHECK = "check"
|
|
|
48
49
|
AGENT_DEBUG = "debug"
|
|
49
50
|
AGENT_RESEARCH = "research"
|
|
50
51
|
|
|
51
|
-
# Agents that require a
|
|
52
|
-
|
|
52
|
+
# Agents that require a task directory
|
|
53
|
+
AGENTS_REQUIRE_TASK = (AGENT_IMPLEMENT, AGENT_CHECK, AGENT_DEBUG)
|
|
53
54
|
# All supported agents
|
|
54
55
|
AGENTS_ALL = (AGENT_IMPLEMENT, AGENT_CHECK, AGENT_DEBUG, AGENT_RESEARCH)
|
|
55
56
|
|
|
@@ -69,35 +70,35 @@ def find_repo_root(start_path: str) -> str | None:
|
|
|
69
70
|
return None
|
|
70
71
|
|
|
71
72
|
|
|
72
|
-
def
|
|
73
|
+
def get_current_task(repo_root: str) -> str | None:
|
|
73
74
|
"""
|
|
74
|
-
Read current
|
|
75
|
+
Read current task directory path from .trellis/.current-task
|
|
75
76
|
|
|
76
77
|
Returns:
|
|
77
|
-
|
|
78
|
+
Task directory relative path (relative to repo_root)
|
|
78
79
|
None if not set
|
|
79
80
|
"""
|
|
80
|
-
|
|
81
|
-
if not os.path.exists(
|
|
81
|
+
current_task_file = os.path.join(repo_root, DIR_WORKFLOW, FILE_CURRENT_TASK)
|
|
82
|
+
if not os.path.exists(current_task_file):
|
|
82
83
|
return None
|
|
83
84
|
|
|
84
85
|
try:
|
|
85
|
-
with open(
|
|
86
|
+
with open(current_task_file, "r", encoding="utf-8") as f:
|
|
86
87
|
content = f.read().strip()
|
|
87
88
|
return content if content else None
|
|
88
89
|
except Exception:
|
|
89
90
|
return None
|
|
90
91
|
|
|
91
92
|
|
|
92
|
-
def update_current_phase(repo_root: str,
|
|
93
|
+
def update_current_phase(repo_root: str, task_dir: str, subagent_type: str) -> None:
|
|
93
94
|
"""
|
|
94
|
-
Update current_phase in
|
|
95
|
+
Update current_phase in task.json based on subagent_type.
|
|
95
96
|
|
|
96
97
|
This ensures phase tracking is always accurate, regardless of whether
|
|
97
98
|
dispatch agent remembers to update it.
|
|
98
99
|
|
|
99
100
|
Logic:
|
|
100
|
-
- Read next_action array from
|
|
101
|
+
- Read next_action array from task.json
|
|
101
102
|
- Find the next phase whose action matches subagent_type
|
|
102
103
|
- Only move forward, never backward
|
|
103
104
|
- Some agents (debug, research) don't update phase
|
|
@@ -105,16 +106,16 @@ def update_current_phase(repo_root: str, feature_dir: str, subagent_type: str) -
|
|
|
105
106
|
if subagent_type in AGENTS_NO_PHASE_UPDATE:
|
|
106
107
|
return
|
|
107
108
|
|
|
108
|
-
|
|
109
|
-
if not os.path.exists(
|
|
109
|
+
task_json_path = os.path.join(repo_root, task_dir, FILE_TASK_JSON)
|
|
110
|
+
if not os.path.exists(task_json_path):
|
|
110
111
|
return
|
|
111
112
|
|
|
112
113
|
try:
|
|
113
|
-
with open(
|
|
114
|
-
|
|
114
|
+
with open(task_json_path, "r", encoding="utf-8") as f:
|
|
115
|
+
task_data = json.load(f)
|
|
115
116
|
|
|
116
|
-
current_phase =
|
|
117
|
-
next_actions =
|
|
117
|
+
current_phase = task_data.get("current_phase", 0)
|
|
118
|
+
next_actions = task_data.get("next_action", [])
|
|
118
119
|
|
|
119
120
|
# Map action names to subagent types
|
|
120
121
|
# "implement" -> "implement", "check" -> "check", "finish" -> "check"
|
|
@@ -137,10 +138,10 @@ def update_current_phase(repo_root: str, feature_dir: str, subagent_type: str) -
|
|
|
137
138
|
break
|
|
138
139
|
|
|
139
140
|
if new_phase is not None:
|
|
140
|
-
|
|
141
|
+
task_data["current_phase"] = new_phase
|
|
141
142
|
|
|
142
|
-
with open(
|
|
143
|
-
json.dump(
|
|
143
|
+
with open(task_json_path, "w", encoding="utf-8") as f:
|
|
144
|
+
json.dump(task_data, f, indent=2, ensure_ascii=False)
|
|
144
145
|
except Exception:
|
|
145
146
|
# Don't fail the hook if phase update fails
|
|
146
147
|
pass
|
|
@@ -249,7 +250,7 @@ def read_jsonl_entries(base_path: str, jsonl_path: str) -> list[tuple[str, str]]
|
|
|
249
250
|
return results
|
|
250
251
|
|
|
251
252
|
|
|
252
|
-
def get_agent_context(repo_root: str,
|
|
253
|
+
def get_agent_context(repo_root: str, task_dir: str, agent_type: str) -> str:
|
|
253
254
|
"""
|
|
254
255
|
Get complete context for specified agent
|
|
255
256
|
|
|
@@ -258,12 +259,12 @@ def get_agent_context(repo_root: str, feature_dir: str, agent_type: str) -> str:
|
|
|
258
259
|
context_parts = []
|
|
259
260
|
|
|
260
261
|
# 1. Try agent-specific jsonl
|
|
261
|
-
agent_jsonl = f"{
|
|
262
|
+
agent_jsonl = f"{task_dir}/{agent_type}.jsonl"
|
|
262
263
|
agent_entries = read_jsonl_entries(repo_root, agent_jsonl)
|
|
263
264
|
|
|
264
265
|
# 2. If agent-specific jsonl doesn't exist or empty, fallback to spec.jsonl
|
|
265
266
|
if not agent_entries:
|
|
266
|
-
agent_entries = read_jsonl_entries(repo_root, f"{
|
|
267
|
+
agent_entries = read_jsonl_entries(repo_root, f"{task_dir}/spec.jsonl")
|
|
267
268
|
|
|
268
269
|
# 3. Add all files from jsonl
|
|
269
270
|
for file_path, content in agent_entries:
|
|
@@ -272,7 +273,7 @@ def get_agent_context(repo_root: str, feature_dir: str, agent_type: str) -> str:
|
|
|
272
273
|
return "\n\n".join(context_parts)
|
|
273
274
|
|
|
274
275
|
|
|
275
|
-
def get_implement_context(repo_root: str,
|
|
276
|
+
def get_implement_context(repo_root: str, task_dir: str) -> str:
|
|
276
277
|
"""
|
|
277
278
|
Complete context for Implement Agent
|
|
278
279
|
|
|
@@ -284,39 +285,39 @@ def get_implement_context(repo_root: str, feature_dir: str) -> str:
|
|
|
284
285
|
context_parts = []
|
|
285
286
|
|
|
286
287
|
# 1. Read implement.jsonl (or fallback to spec.jsonl)
|
|
287
|
-
base_context = get_agent_context(repo_root,
|
|
288
|
+
base_context = get_agent_context(repo_root, task_dir, "implement")
|
|
288
289
|
if base_context:
|
|
289
290
|
context_parts.append(base_context)
|
|
290
291
|
|
|
291
292
|
# 2. Requirements document
|
|
292
|
-
prd_content = read_file_content(repo_root, f"{
|
|
293
|
+
prd_content = read_file_content(repo_root, f"{task_dir}/prd.md")
|
|
293
294
|
if prd_content:
|
|
294
295
|
context_parts.append(
|
|
295
|
-
f"=== {
|
|
296
|
+
f"=== {task_dir}/prd.md (Requirements) ===\n{prd_content}"
|
|
296
297
|
)
|
|
297
298
|
|
|
298
299
|
# 3. Technical design
|
|
299
|
-
info_content = read_file_content(repo_root, f"{
|
|
300
|
+
info_content = read_file_content(repo_root, f"{task_dir}/info.md")
|
|
300
301
|
if info_content:
|
|
301
302
|
context_parts.append(
|
|
302
|
-
f"=== {
|
|
303
|
+
f"=== {task_dir}/info.md (Technical Design) ===\n{info_content}"
|
|
303
304
|
)
|
|
304
305
|
|
|
305
306
|
return "\n\n".join(context_parts)
|
|
306
307
|
|
|
307
308
|
|
|
308
|
-
def get_check_context(repo_root: str,
|
|
309
|
+
def get_check_context(repo_root: str, task_dir: str) -> str:
|
|
309
310
|
"""
|
|
310
311
|
Complete context for Check Agent
|
|
311
312
|
|
|
312
313
|
Read order:
|
|
313
314
|
1. All files in check.jsonl (check specs + dev specs)
|
|
314
|
-
2. prd.md (for understanding
|
|
315
|
+
2. prd.md (for understanding task intent)
|
|
315
316
|
"""
|
|
316
317
|
context_parts = []
|
|
317
318
|
|
|
318
319
|
# 1. Read check.jsonl (or fallback to spec.jsonl + hardcoded check files)
|
|
319
|
-
check_entries = read_jsonl_entries(repo_root, f"{
|
|
320
|
+
check_entries = read_jsonl_entries(repo_root, f"{task_dir}/check.jsonl")
|
|
320
321
|
|
|
321
322
|
if check_entries:
|
|
322
323
|
for file_path, content in check_entries:
|
|
@@ -335,21 +336,21 @@ def get_check_context(repo_root: str, feature_dir: str) -> str:
|
|
|
335
336
|
context_parts.append(f"=== {file_path} ({description}) ===\n{content}")
|
|
336
337
|
|
|
337
338
|
# Add spec.jsonl
|
|
338
|
-
spec_entries = read_jsonl_entries(repo_root, f"{
|
|
339
|
+
spec_entries = read_jsonl_entries(repo_root, f"{task_dir}/spec.jsonl")
|
|
339
340
|
for file_path, content in spec_entries:
|
|
340
341
|
context_parts.append(f"=== {file_path} (Dev spec) ===\n{content}")
|
|
341
342
|
|
|
342
|
-
# 2. Requirements document (for understanding
|
|
343
|
-
prd_content = read_file_content(repo_root, f"{
|
|
343
|
+
# 2. Requirements document (for understanding task intent)
|
|
344
|
+
prd_content = read_file_content(repo_root, f"{task_dir}/prd.md")
|
|
344
345
|
if prd_content:
|
|
345
346
|
context_parts.append(
|
|
346
|
-
f"=== {
|
|
347
|
+
f"=== {task_dir}/prd.md (Requirements - for understanding intent) ===\n{prd_content}"
|
|
347
348
|
)
|
|
348
349
|
|
|
349
350
|
return "\n\n".join(context_parts)
|
|
350
351
|
|
|
351
352
|
|
|
352
|
-
def get_finish_context(repo_root: str,
|
|
353
|
+
def get_finish_context(repo_root: str, task_dir: str) -> str:
|
|
353
354
|
"""
|
|
354
355
|
Complete context for Finish phase (final check before PR)
|
|
355
356
|
|
|
@@ -361,7 +362,7 @@ def get_finish_context(repo_root: str, feature_dir: str) -> str:
|
|
|
361
362
|
context_parts = []
|
|
362
363
|
|
|
363
364
|
# 1. Try finish.jsonl first
|
|
364
|
-
finish_entries = read_jsonl_entries(repo_root, f"{
|
|
365
|
+
finish_entries = read_jsonl_entries(repo_root, f"{task_dir}/finish.jsonl")
|
|
365
366
|
|
|
366
367
|
if finish_entries:
|
|
367
368
|
for file_path, content in finish_entries:
|
|
@@ -375,16 +376,16 @@ def get_finish_context(repo_root: str, feature_dir: str) -> str:
|
|
|
375
376
|
)
|
|
376
377
|
|
|
377
378
|
# 2. Requirements document (for verifying requirements are met)
|
|
378
|
-
prd_content = read_file_content(repo_root, f"{
|
|
379
|
+
prd_content = read_file_content(repo_root, f"{task_dir}/prd.md")
|
|
379
380
|
if prd_content:
|
|
380
381
|
context_parts.append(
|
|
381
|
-
f"=== {
|
|
382
|
+
f"=== {task_dir}/prd.md (Requirements - verify all met) ===\n{prd_content}"
|
|
382
383
|
)
|
|
383
384
|
|
|
384
385
|
return "\n\n".join(context_parts)
|
|
385
386
|
|
|
386
387
|
|
|
387
|
-
def get_debug_context(repo_root: str,
|
|
388
|
+
def get_debug_context(repo_root: str, task_dir: str) -> str:
|
|
388
389
|
"""
|
|
389
390
|
Complete context for Debug Agent
|
|
390
391
|
|
|
@@ -395,14 +396,14 @@ def get_debug_context(repo_root: str, feature_dir: str) -> str:
|
|
|
395
396
|
context_parts = []
|
|
396
397
|
|
|
397
398
|
# 1. Read debug.jsonl (or fallback to spec.jsonl + hardcoded check files)
|
|
398
|
-
debug_entries = read_jsonl_entries(repo_root, f"{
|
|
399
|
+
debug_entries = read_jsonl_entries(repo_root, f"{task_dir}/debug.jsonl")
|
|
399
400
|
|
|
400
401
|
if debug_entries:
|
|
401
402
|
for file_path, content in debug_entries:
|
|
402
403
|
context_parts.append(f"=== {file_path} ===\n{content}")
|
|
403
404
|
else:
|
|
404
405
|
# Fallback: use spec.jsonl + hardcoded check files
|
|
405
|
-
spec_entries = read_jsonl_entries(repo_root, f"{
|
|
406
|
+
spec_entries = read_jsonl_entries(repo_root, f"{task_dir}/spec.jsonl")
|
|
406
407
|
for file_path, content in spec_entries:
|
|
407
408
|
context_parts.append(f"=== {file_path} (Dev spec) ===\n{content}")
|
|
408
409
|
|
|
@@ -418,11 +419,11 @@ def get_debug_context(repo_root: str, feature_dir: str) -> str:
|
|
|
418
419
|
|
|
419
420
|
# 2. Codex review output (if exists)
|
|
420
421
|
codex_output = read_file_content(
|
|
421
|
-
repo_root, f"{
|
|
422
|
+
repo_root, f"{task_dir}/codex-review-output.txt"
|
|
422
423
|
)
|
|
423
424
|
if codex_output:
|
|
424
425
|
context_parts.append(
|
|
425
|
-
f"=== {
|
|
426
|
+
f"=== {task_dir}/codex-review-output.txt (Codex Review Results) ===\n{codex_output}"
|
|
426
427
|
)
|
|
427
428
|
|
|
428
429
|
return "\n\n".join(context_parts)
|
|
@@ -564,7 +565,7 @@ Dev specs and Codex Review results:
|
|
|
564
565
|
- Report which issues were fixed and which files were modified"""
|
|
565
566
|
|
|
566
567
|
|
|
567
|
-
def get_research_context(repo_root: str,
|
|
568
|
+
def get_research_context(repo_root: str, task_dir: str | None) -> str:
|
|
568
569
|
"""
|
|
569
570
|
Context for Research Agent
|
|
570
571
|
|
|
@@ -575,11 +576,11 @@ def get_research_context(repo_root: str, feature_dir: str | None) -> str:
|
|
|
575
576
|
context_parts = []
|
|
576
577
|
|
|
577
578
|
# 1. Project structure overview (uses constants for paths)
|
|
578
|
-
|
|
579
|
+
spec_path = f"{DIR_WORKFLOW}/{DIR_SPEC}"
|
|
579
580
|
project_structure = f"""## Project Spec Directory Structure
|
|
580
581
|
|
|
581
582
|
```
|
|
582
|
-
{
|
|
583
|
+
{spec_path}/
|
|
583
584
|
├── shared/ # Cross-project common specs (TypeScript, code quality, git)
|
|
584
585
|
├── frontend/ # Frontend standards
|
|
585
586
|
├── backend/ # Backend standards
|
|
@@ -590,17 +591,17 @@ def get_research_context(repo_root: str, feature_dir: str | None) -> str:
|
|
|
590
591
|
|
|
591
592
|
## Search Tips
|
|
592
593
|
|
|
593
|
-
- Spec files: `{
|
|
594
|
+
- Spec files: `{spec_path}/**/*.md`
|
|
594
595
|
- Known issues: `{DIR_WORKFLOW}/big-question/`
|
|
595
596
|
- Code search: Use Glob and Grep tools
|
|
596
597
|
- Tech solutions: Use mcp__exa__web_search_exa or mcp__exa__get_code_context_exa"""
|
|
597
598
|
|
|
598
599
|
context_parts.append(project_structure)
|
|
599
600
|
|
|
600
|
-
# 2. If
|
|
601
|
-
if
|
|
601
|
+
# 2. If task directory exists, try reading research.jsonl (optional)
|
|
602
|
+
if task_dir:
|
|
602
603
|
research_entries = read_jsonl_entries(
|
|
603
|
-
repo_root, f"{
|
|
604
|
+
repo_root, f"{task_dir}/research.jsonl"
|
|
604
605
|
)
|
|
605
606
|
if research_entries:
|
|
606
607
|
context_parts.append(
|
|
@@ -697,46 +698,46 @@ def main():
|
|
|
697
698
|
if not repo_root:
|
|
698
699
|
sys.exit(0)
|
|
699
700
|
|
|
700
|
-
# Get current
|
|
701
|
-
|
|
701
|
+
# Get current task directory (research doesn't require it)
|
|
702
|
+
task_dir = get_current_task(repo_root)
|
|
702
703
|
|
|
703
|
-
# implement/check/debug need
|
|
704
|
-
if subagent_type in
|
|
705
|
-
if not
|
|
704
|
+
# implement/check/debug need task directory
|
|
705
|
+
if subagent_type in AGENTS_REQUIRE_TASK:
|
|
706
|
+
if not task_dir:
|
|
706
707
|
sys.exit(0)
|
|
707
|
-
# Check if
|
|
708
|
-
|
|
709
|
-
if not os.path.exists(
|
|
708
|
+
# Check if task directory exists
|
|
709
|
+
task_dir_full = os.path.join(repo_root, task_dir)
|
|
710
|
+
if not os.path.exists(task_dir_full):
|
|
710
711
|
sys.exit(0)
|
|
711
712
|
|
|
712
|
-
# Update current_phase in
|
|
713
|
-
update_current_phase(repo_root,
|
|
713
|
+
# Update current_phase in task.json (system-level enforcement)
|
|
714
|
+
update_current_phase(repo_root, task_dir, subagent_type)
|
|
714
715
|
|
|
715
716
|
# Check for [finish] marker in prompt (check agent with finish context)
|
|
716
717
|
is_finish_phase = "[finish]" in original_prompt.lower()
|
|
717
718
|
|
|
718
719
|
# Get context and build prompt based on subagent type
|
|
719
720
|
if subagent_type == AGENT_IMPLEMENT:
|
|
720
|
-
assert
|
|
721
|
-
context = get_implement_context(repo_root,
|
|
721
|
+
assert task_dir is not None # validated above
|
|
722
|
+
context = get_implement_context(repo_root, task_dir)
|
|
722
723
|
new_prompt = build_implement_prompt(original_prompt, context)
|
|
723
724
|
elif subagent_type == AGENT_CHECK:
|
|
724
|
-
assert
|
|
725
|
+
assert task_dir is not None # validated above
|
|
725
726
|
if is_finish_phase:
|
|
726
727
|
# Finish phase: use finish context (lighter, focused on final verification)
|
|
727
|
-
context = get_finish_context(repo_root,
|
|
728
|
+
context = get_finish_context(repo_root, task_dir)
|
|
728
729
|
new_prompt = build_finish_prompt(original_prompt, context)
|
|
729
730
|
else:
|
|
730
731
|
# Regular check phase: use check context (full specs for self-fix loop)
|
|
731
|
-
context = get_check_context(repo_root,
|
|
732
|
+
context = get_check_context(repo_root, task_dir)
|
|
732
733
|
new_prompt = build_check_prompt(original_prompt, context)
|
|
733
734
|
elif subagent_type == AGENT_DEBUG:
|
|
734
|
-
assert
|
|
735
|
-
context = get_debug_context(repo_root,
|
|
735
|
+
assert task_dir is not None # validated above
|
|
736
|
+
context = get_debug_context(repo_root, task_dir)
|
|
736
737
|
new_prompt = build_debug_prompt(original_prompt, context)
|
|
737
738
|
elif subagent_type == AGENT_RESEARCH:
|
|
738
|
-
# Research can work without
|
|
739
|
-
context = get_research_context(repo_root,
|
|
739
|
+
# Research can work without task directory
|
|
740
|
+
context = get_research_context(repo_root, task_dir)
|
|
740
741
|
new_prompt = build_research_prompt(original_prompt, context)
|
|
741
742
|
else:
|
|
742
743
|
sys.exit(0)
|