@mindfoldhq/trellis 0.4.0-beta.7 → 0.4.0-beta.9
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 +10 -5
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +34 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +33 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/codex.d.ts +7 -4
- package/dist/configurators/codex.d.ts.map +1 -1
- package/dist/configurators/codex.js +40 -10
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/copilot.d.ts +9 -0
- package/dist/configurators/copilot.d.ts.map +1 -0
- package/dist/configurators/copilot.js +34 -0
- package/dist/configurators/copilot.js.map +1 -0
- package/dist/configurators/index.d.ts +11 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +59 -4
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/windsurf.d.ts +8 -0
- package/dist/configurators/windsurf.d.ts.map +1 -0
- package/dist/configurators/windsurf.js +18 -0
- package/dist/configurators/windsurf.js.map +1 -0
- package/dist/migrations/manifests/0.4.0-beta.8.json +34 -0
- package/dist/migrations/manifests/0.4.0-beta.9.json +9 -0
- package/dist/templates/claude/commands/trellis/record-session.md +2 -1
- package/dist/templates/claude/hooks/inject-subagent-context.py +8 -1
- package/dist/templates/claude/hooks/ralph-loop.py +8 -1
- package/dist/templates/claude/hooks/session-start.py +31 -7
- package/dist/templates/claude/hooks/statusline.py +211 -0
- package/dist/templates/claude/settings.json +4 -0
- package/dist/templates/codex/agents/check.toml +23 -0
- package/dist/templates/codex/agents/implement.toml +19 -0
- package/dist/templates/codex/agents/research.toml +26 -0
- package/dist/templates/codex/codex-skills/parallel/SKILL.md +194 -0
- package/dist/templates/codex/config.toml +5 -0
- package/dist/templates/codex/hooks/session-start.py +228 -0
- package/dist/templates/codex/hooks.json +16 -0
- package/dist/templates/codex/index.d.ts +27 -5
- package/dist/templates/codex/index.d.ts.map +1 -1
- package/dist/templates/codex/index.js +60 -8
- package/dist/templates/codex/index.js.map +1 -1
- package/dist/templates/codex/skills/improve-ut/SKILL.md +69 -0
- package/dist/templates/codex/skills/record-session/SKILL.md +2 -1
- package/dist/templates/copilot/hooks/session-start.py +218 -0
- package/dist/templates/copilot/hooks.json +11 -0
- package/dist/templates/copilot/index.d.ts +23 -0
- package/dist/templates/copilot/index.d.ts.map +1 -0
- package/dist/templates/copilot/index.js +54 -0
- package/dist/templates/copilot/index.js.map +1 -0
- package/dist/templates/copilot/prompts/before-dev.prompt.md +33 -0
- package/dist/templates/copilot/prompts/brainstorm.prompt.md +491 -0
- package/dist/templates/copilot/prompts/break-loop.prompt.md +129 -0
- package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +157 -0
- package/dist/templates/copilot/prompts/check.prompt.md +29 -0
- package/dist/templates/copilot/prompts/create-command.prompt.md +116 -0
- package/dist/templates/copilot/prompts/finish-work.prompt.md +157 -0
- package/dist/templates/copilot/prompts/integrate-skill.prompt.md +223 -0
- package/dist/templates/copilot/prompts/onboard.prompt.md +362 -0
- package/dist/templates/copilot/prompts/parallel.prompt.md +196 -0
- package/dist/templates/copilot/prompts/record-session.prompt.md +66 -0
- package/dist/templates/copilot/prompts/start.prompt.md +397 -0
- package/dist/templates/copilot/prompts/update-spec.prompt.md +358 -0
- package/dist/templates/cursor/commands/trellis-record-session.md +2 -1
- package/dist/templates/extract.d.ts +29 -0
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +51 -0
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/gemini/commands/trellis/record-session.toml +2 -1
- package/dist/templates/iflow/commands/trellis/record-session.md +2 -1
- package/dist/templates/iflow/hooks/inject-subagent-context.py +8 -1
- package/dist/templates/iflow/hooks/ralph-loop.py +8 -1
- package/dist/templates/iflow/hooks/session-start.py +31 -7
- package/dist/templates/kilo/workflows/record-session.md +2 -1
- package/dist/templates/kiro/skills/record-session/SKILL.md +2 -1
- package/dist/templates/markdown/agents.md +4 -0
- package/dist/templates/markdown/spec/backend/directory-structure.md +1 -1
- package/dist/templates/markdown/workspace-index.md +2 -0
- package/dist/templates/opencode/agents/dispatch.md +20 -19
- package/dist/templates/opencode/commands/trellis/record-session.md +2 -1
- package/dist/templates/opencode/lib/trellis-context.js +42 -2
- package/dist/templates/opencode/plugins/session-start.js +7 -27
- package/dist/templates/qoder/skills/record-session/SKILL.md +2 -1
- package/dist/templates/trellis/scripts/add_session.py +69 -16
- package/dist/templates/trellis/scripts/common/__init__.py +2 -0
- package/dist/templates/trellis/scripts/common/cli_adapter.py +108 -16
- package/dist/templates/trellis/scripts/common/developer.py +2 -2
- package/dist/templates/trellis/scripts/common/paths.py +57 -6
- package/dist/templates/trellis/scripts/common/task_store.py +6 -4
- package/dist/templates/trellis/scripts/common/task_utils.py +14 -8
- package/dist/templates/trellis/scripts/multi_agent/plan.py +7 -6
- package/dist/templates/trellis/scripts/multi_agent/start.py +16 -11
- package/dist/templates/trellis/scripts/task.py +1 -1
- package/dist/templates/windsurf/index.d.ts +21 -0
- package/dist/templates/windsurf/index.d.ts.map +1 -0
- package/dist/templates/windsurf/index.js +44 -0
- package/dist/templates/windsurf/index.js.map +1 -0
- package/dist/templates/windsurf/workflows/trellis-before-dev.md +31 -0
- package/dist/templates/windsurf/workflows/trellis-brainstorm.md +491 -0
- package/dist/templates/windsurf/workflows/trellis-break-loop.md +111 -0
- package/dist/templates/windsurf/workflows/trellis-check-cross-layer.md +157 -0
- package/dist/templates/windsurf/workflows/trellis-check.md +27 -0
- package/dist/templates/windsurf/workflows/trellis-create-command.md +154 -0
- package/dist/templates/windsurf/workflows/trellis-finish-work.md +147 -0
- package/dist/templates/windsurf/workflows/trellis-integrate-skill.md +220 -0
- package/dist/templates/windsurf/workflows/trellis-onboard.md +362 -0
- package/dist/templates/windsurf/workflows/trellis-record-session.md +66 -0
- package/dist/templates/windsurf/workflows/trellis-start.md +373 -0
- package/dist/templates/windsurf/workflows/trellis-update-spec.md +358 -0
- package/dist/types/ai-tools.d.ts +15 -3
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +34 -2
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/template-fetcher.d.ts +17 -4
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +94 -12
- package/dist/utils/template-fetcher.js.map +1 -1
- package/package.json +1 -1
|
@@ -51,6 +51,7 @@ EOF
|
|
|
51
51
|
**Auto-completes**:
|
|
52
52
|
- [OK] Appends session to journal-N.md
|
|
53
53
|
- [OK] Auto-detects line count, creates new file if >2000 lines
|
|
54
|
+
- [OK] Auto-detects Branch context (`--branch` override; otherwise Branch = task.json -> current git branch; missing values are omitted gracefully)
|
|
54
55
|
- [OK] Updates index.md (Total Sessions +1, Last Active, line stats, history)
|
|
55
56
|
- [OK] Auto-commits .trellis/workspace and .trellis/tasks changes
|
|
56
57
|
|
|
@@ -61,6 +62,6 @@ EOF
|
|
|
61
62
|
| Command | Purpose |
|
|
62
63
|
|---------|---------|
|
|
63
64
|
| `python3 ./.trellis/scripts/get_context.py --mode record` | Get context for record-session |
|
|
64
|
-
| `python3 ./.trellis/scripts/add_session.py --title "..." --commit "..."` | **One-click add session (recommended)** |
|
|
65
|
+
| `python3 ./.trellis/scripts/add_session.py --title "..." --commit "..."` | **One-click add session (recommended, branch auto-complete)** |
|
|
65
66
|
| `python3 ./.trellis/scripts/task.py archive <name>` | Archive completed task (auto-commits) |
|
|
66
67
|
| `python3 ./.trellis/scripts/task.py list` | List active tasks |
|
|
@@ -13,6 +13,10 @@ Use `@/.trellis/` to learn:
|
|
|
13
13
|
- Project structure guidelines (`spec/`)
|
|
14
14
|
- Developer workspace (`workspace/`)
|
|
15
15
|
|
|
16
|
+
If you're using Codex, project-scoped helpers may also live in:
|
|
17
|
+
- `.agents/skills/` for reusable Trellis skills
|
|
18
|
+
- `.codex/agents/` for optional custom subagents
|
|
19
|
+
|
|
16
20
|
Keep this managed block so 'trellis update' can refresh the instructions.
|
|
17
21
|
|
|
18
22
|
<!-- TRELLIS:END -->
|
|
@@ -239,7 +239,7 @@ Templates use `.txt` extension to:
|
|
|
239
239
|
```typescript
|
|
240
240
|
import { downloadTemplate } from "giget";
|
|
241
241
|
|
|
242
|
-
await downloadTemplate("gh:mindfold-ai/
|
|
242
|
+
await downloadTemplate("gh:mindfold-ai/marketplace/specs/electron-fullstack", {
|
|
243
243
|
dir: destDir,
|
|
244
244
|
preferOffline: true,
|
|
245
245
|
});
|
|
@@ -73,6 +73,7 @@ This will:
|
|
|
73
73
|
|
|
74
74
|
Each session should include:
|
|
75
75
|
- Summary: One-line description
|
|
76
|
+
- Branch: Which branch the work was done on
|
|
76
77
|
- Main Changes: What was modified
|
|
77
78
|
- Git Commits: Commit hashes and messages
|
|
78
79
|
- Next Steps: What to do next
|
|
@@ -88,6 +89,7 @@ Use this template when recording sessions:
|
|
|
88
89
|
|
|
89
90
|
**Date**: YYYY-MM-DD
|
|
90
91
|
**Task**: {task-name}
|
|
92
|
+
**Branch**: `{branch-name}`
|
|
91
93
|
|
|
92
94
|
### Summary
|
|
93
95
|
|
|
@@ -71,6 +71,10 @@ Execute each step in `phase` order.
|
|
|
71
71
|
|
|
72
72
|
> Hook will auto-inject all specs, requirements, and technical design to subagent context.
|
|
73
73
|
> Dispatch only needs to issue simple call commands.
|
|
74
|
+
>
|
|
75
|
+
> **OpenCode dispatch rule**: Call subagents synchronously (`run_in_background: false`).
|
|
76
|
+
> Do NOT use `TaskOutput` or background polling as the completion signal for child phases.
|
|
77
|
+
> The background wrapper can finish before the real subagent session is actually done.
|
|
74
78
|
|
|
75
79
|
### action: "implement"
|
|
76
80
|
|
|
@@ -79,7 +83,7 @@ Task(
|
|
|
79
83
|
subagent_type: "implement",
|
|
80
84
|
prompt: "Implement the feature described in prd.md in the task directory",
|
|
81
85
|
model: "opus",
|
|
82
|
-
run_in_background:
|
|
86
|
+
run_in_background: false
|
|
83
87
|
)
|
|
84
88
|
```
|
|
85
89
|
|
|
@@ -98,7 +102,7 @@ Task(
|
|
|
98
102
|
subagent_type: "check",
|
|
99
103
|
prompt: "Check code changes, fix issues yourself",
|
|
100
104
|
model: "opus",
|
|
101
|
-
run_in_background:
|
|
105
|
+
run_in_background: false
|
|
102
106
|
)
|
|
103
107
|
```
|
|
104
108
|
|
|
@@ -116,7 +120,7 @@ Task(
|
|
|
116
120
|
subagent_type: "debug",
|
|
117
121
|
prompt: "Fix the issues described in the task context",
|
|
118
122
|
model: "opus",
|
|
119
|
-
run_in_background:
|
|
123
|
+
run_in_background: false
|
|
120
124
|
)
|
|
121
125
|
```
|
|
122
126
|
|
|
@@ -132,7 +136,7 @@ Task(
|
|
|
132
136
|
subagent_type: "check",
|
|
133
137
|
prompt: "[finish] Execute final completion check before PR",
|
|
134
138
|
model: "opus",
|
|
135
|
-
run_in_background:
|
|
139
|
+
run_in_background: false
|
|
136
140
|
)
|
|
137
141
|
```
|
|
138
142
|
|
|
@@ -168,27 +172,23 @@ This will:
|
|
|
168
172
|
### Basic Pattern
|
|
169
173
|
|
|
170
174
|
```
|
|
171
|
-
|
|
175
|
+
result = Task(
|
|
172
176
|
subagent_type: "implement", // or "check", "debug"
|
|
173
177
|
prompt: "Simple task description",
|
|
174
178
|
model: "opus",
|
|
175
|
-
run_in_background:
|
|
179
|
+
run_in_background: false
|
|
176
180
|
)
|
|
177
181
|
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
result = TaskOutput(task_id, block=true, timeout=300000)
|
|
181
|
-
if result.status == "completed":
|
|
182
|
-
break
|
|
182
|
+
// Wait for the Task call to return before starting the next phase.
|
|
183
|
+
// Do NOT call TaskOutput or use background polling inside OpenCode dispatch.
|
|
183
184
|
```
|
|
184
185
|
|
|
185
|
-
###
|
|
186
|
+
### Execution Rule
|
|
186
187
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
| debug | 20 min | 4 times |
|
|
188
|
+
- Run one phase at a time
|
|
189
|
+
- Start the next phase only after the current `Task(...)` call returns
|
|
190
|
+
- If a phase returns a clear timeout or failure, handle that result explicitly
|
|
191
|
+
- Do **not** simulate completion by polling a background task wrapper
|
|
192
192
|
|
|
193
193
|
---
|
|
194
194
|
|
|
@@ -196,7 +196,7 @@ for i in 1..N:
|
|
|
196
196
|
|
|
197
197
|
### Timeout
|
|
198
198
|
|
|
199
|
-
If a subagent times out, notify the user and ask for guidance:
|
|
199
|
+
If a synchronous subagent call times out, notify the user and ask for guidance:
|
|
200
200
|
|
|
201
201
|
```
|
|
202
202
|
"Subagent {phase} timed out after {time}. Options:
|
|
@@ -207,10 +207,11 @@ If a subagent times out, notify the user and ask for guidance:
|
|
|
207
207
|
|
|
208
208
|
### Subagent Failure
|
|
209
209
|
|
|
210
|
-
If a subagent reports failure, read the output and decide:
|
|
210
|
+
If a synchronous subagent call reports failure, read the output and decide:
|
|
211
211
|
|
|
212
212
|
- If recoverable: call debug agent to fix
|
|
213
213
|
- If not recoverable: notify user and ask for guidance
|
|
214
|
+
- Do not switch back to `TaskOutput` polling for the same phase
|
|
214
215
|
|
|
215
216
|
---
|
|
216
217
|
|
|
@@ -46,6 +46,7 @@ EOF
|
|
|
46
46
|
**Auto-completes**:
|
|
47
47
|
- [OK] Appends session to journal-N.md
|
|
48
48
|
- [OK] Auto-detects line count, creates new file if >2000 lines
|
|
49
|
+
- [OK] Auto-detects Branch context (`--branch` override; otherwise Branch = task.json -> current git branch; missing values are omitted gracefully)
|
|
49
50
|
- [OK] Updates index.md (Total Sessions +1, Last Active, line stats, history)
|
|
50
51
|
- [OK] Auto-commits .trellis/workspace and .trellis/tasks changes
|
|
51
52
|
|
|
@@ -56,6 +57,6 @@ EOF
|
|
|
56
57
|
| Command | Purpose |
|
|
57
58
|
|---------|---------|
|
|
58
59
|
| `python3 ./.trellis/scripts/get_context.py --mode record` | Get context for record-session |
|
|
59
|
-
| `python3 ./.trellis/scripts/add_session.py --title "..." --commit "..."` | **One-click add session (recommended)** |
|
|
60
|
+
| `python3 ./.trellis/scripts/add_session.py --title "..." --commit "..."` | **One-click add session (recommended, branch auto-complete)** |
|
|
60
61
|
| `python3 ./.trellis/scripts/task.py archive <name>` | Archive completed task (auto-commits) |
|
|
61
62
|
| `python3 ./.trellis/scripts/task.py list` | List active tasks |
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { existsSync, readFileSync, appendFileSync, readdirSync } from "fs"
|
|
14
|
-
import { join } from "path"
|
|
14
|
+
import { isAbsolute, join } from "path"
|
|
15
15
|
import { homedir, platform } from "os"
|
|
16
16
|
import { execSync } from "child_process"
|
|
17
17
|
|
|
@@ -191,12 +191,52 @@ export class TrellisContext {
|
|
|
191
191
|
if (!existsSync(currentTaskPath)) {
|
|
192
192
|
return null
|
|
193
193
|
}
|
|
194
|
-
|
|
194
|
+
const taskRef = readFileSync(currentTaskPath, "utf-8").trim()
|
|
195
|
+
const normalized = this.normalizeTaskRef(taskRef)
|
|
196
|
+
return normalized || null
|
|
195
197
|
} catch {
|
|
196
198
|
return null
|
|
197
199
|
}
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
normalizeTaskRef(taskRef) {
|
|
203
|
+
if (!taskRef) {
|
|
204
|
+
return ""
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (isAbsolute(taskRef)) {
|
|
208
|
+
return taskRef.trim()
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let normalized = taskRef.trim().replace(/\\/g, "/")
|
|
212
|
+
while (normalized.startsWith("./")) {
|
|
213
|
+
normalized = normalized.slice(2)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (normalized.startsWith("tasks/")) {
|
|
217
|
+
return `.trellis/${normalized}`
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return normalized
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
resolveTaskDir(taskRef) {
|
|
224
|
+
const normalized = this.normalizeTaskRef(taskRef)
|
|
225
|
+
if (!normalized) {
|
|
226
|
+
return null
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (isAbsolute(normalized)) {
|
|
230
|
+
return normalized
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (normalized.startsWith(".trellis/")) {
|
|
234
|
+
return join(this.directory, normalized)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return join(this.directory, ".trellis", "tasks", normalized)
|
|
238
|
+
}
|
|
239
|
+
|
|
200
240
|
// ============================================================
|
|
201
241
|
// Hook Decision Logic
|
|
202
242
|
// ============================================================
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { existsSync, readFileSync, readdirSync, statSync } from "fs"
|
|
14
|
-
import { join } from "path"
|
|
14
|
+
import { basename, join } from "path"
|
|
15
15
|
import { execFileSync } from "child_process"
|
|
16
16
|
import { platform } from "os"
|
|
17
17
|
import { TrellisContext, contextCollector, debugLog } from "../lib/trellis-context.js"
|
|
@@ -23,36 +23,16 @@ const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
|
|
|
23
23
|
* Check current task status and return structured status string.
|
|
24
24
|
* JavaScript equivalent of _get_task_status in Claude's session-start.py.
|
|
25
25
|
*/
|
|
26
|
-
function getTaskStatus(
|
|
27
|
-
const
|
|
28
|
-
const currentTaskFile = join(trellisDir, ".current-task")
|
|
29
|
-
|
|
30
|
-
if (!existsSync(currentTaskFile)) {
|
|
31
|
-
return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let taskRef
|
|
35
|
-
try {
|
|
36
|
-
taskRef = readFileSync(currentTaskFile, "utf-8").trim()
|
|
37
|
-
} catch {
|
|
38
|
-
return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
|
|
39
|
-
}
|
|
40
|
-
|
|
26
|
+
function getTaskStatus(ctx) {
|
|
27
|
+
const taskRef = ctx.getCurrentTask()
|
|
41
28
|
if (!taskRef) {
|
|
42
29
|
return "Status: NO ACTIVE TASK\nNext: Describe what you want to work on"
|
|
43
30
|
}
|
|
44
31
|
|
|
45
32
|
// Resolve task directory
|
|
46
|
-
|
|
47
|
-
if (taskRef.startsWith("/")) {
|
|
48
|
-
taskDir = taskRef
|
|
49
|
-
} else if (taskRef.startsWith(".trellis/")) {
|
|
50
|
-
taskDir = join(directory, taskRef)
|
|
51
|
-
} else {
|
|
52
|
-
taskDir = join(trellisDir, "tasks", taskRef)
|
|
53
|
-
}
|
|
33
|
+
const taskDir = ctx.resolveTaskDir(taskRef)
|
|
54
34
|
|
|
55
|
-
if (!existsSync(taskDir)) {
|
|
35
|
+
if (!taskDir || !existsSync(taskDir)) {
|
|
56
36
|
return `Status: STALE POINTER\nTask: ${taskRef}\nNext: Task directory not found. Run: python3 ./.trellis/scripts/task.py finish`
|
|
57
37
|
}
|
|
58
38
|
|
|
@@ -71,7 +51,7 @@ function getTaskStatus(directory) {
|
|
|
71
51
|
const taskStatus = taskData.status || "unknown"
|
|
72
52
|
|
|
73
53
|
if (taskStatus === "completed") {
|
|
74
|
-
const dirName = taskDir
|
|
54
|
+
const dirName = basename(taskDir)
|
|
75
55
|
return `Status: COMPLETED\nTask: ${taskTitle}\nNext: Archive with \`python3 ./.trellis/scripts/task.py archive ${dirName}\` or start a new task`
|
|
76
56
|
}
|
|
77
57
|
|
|
@@ -354,7 +334,7 @@ Read and follow all instructions below carefully.
|
|
|
354
334
|
}
|
|
355
335
|
|
|
356
336
|
// 6. Task status (R2: check task state for session resume)
|
|
357
|
-
const taskStatus = getTaskStatus(
|
|
337
|
+
const taskStatus = getTaskStatus(ctx)
|
|
358
338
|
parts.push(`<task-status>\n${taskStatus}\n</task-status>`)
|
|
359
339
|
|
|
360
340
|
// 7. Final directive (R3: active, not passive)
|
|
@@ -51,6 +51,7 @@ EOF
|
|
|
51
51
|
**Auto-completes**:
|
|
52
52
|
- [OK] Appends session to journal-N.md
|
|
53
53
|
- [OK] Auto-detects line count, creates new file if >2000 lines
|
|
54
|
+
- [OK] Auto-detects Branch context (`--branch` override; otherwise Branch = task.json -> current git branch; missing values are omitted gracefully)
|
|
54
55
|
- [OK] Updates index.md (Total Sessions +1, Last Active, line stats, history)
|
|
55
56
|
- [OK] Auto-commits .trellis/workspace and .trellis/tasks changes
|
|
56
57
|
|
|
@@ -61,6 +62,6 @@ EOF
|
|
|
61
62
|
| Command | Purpose |
|
|
62
63
|
|---------|---------|
|
|
63
64
|
| `python3 ./.trellis/scripts/get_context.py --mode record` | Get context for record-session |
|
|
64
|
-
| `python3 ./.trellis/scripts/add_session.py --title "..." --commit "..."` | **One-click add session (recommended)** |
|
|
65
|
+
| `python3 ./.trellis/scripts/add_session.py --title "..." --commit "..."` | **One-click add session (recommended, branch auto-complete)** |
|
|
65
66
|
| `python3 ./.trellis/scripts/task.py archive <name>` | Archive completed task (auto-commits) |
|
|
66
67
|
| `python3 ./.trellis/scripts/task.py list` | List active tasks |
|
|
@@ -5,17 +5,23 @@ Add a new session to journal file and update index.md.
|
|
|
5
5
|
|
|
6
6
|
Usage:
|
|
7
7
|
python3 add_session.py --title "Title" --commit "hash" --summary "Summary" [--package cli]
|
|
8
|
+
python3 add_session.py --title "Title" --branch "feat/my-branch"
|
|
8
9
|
|
|
9
10
|
# Pipe detailed content via stdin (use --stdin to opt in):
|
|
10
11
|
cat << 'EOF' | python3 add_session.py --stdin --title "Title" --summary "Summary"
|
|
11
12
|
<session content here>
|
|
12
13
|
EOF
|
|
14
|
+
|
|
15
|
+
Branch resolution order:
|
|
16
|
+
1. --branch CLI arg (explicit)
|
|
17
|
+
2. task.json branch field (from active task)
|
|
18
|
+
3. git branch --show-current (auto-detect)
|
|
19
|
+
4. None (omitted gracefully)
|
|
13
20
|
"""
|
|
14
21
|
|
|
15
22
|
from __future__ import annotations
|
|
16
23
|
|
|
17
24
|
import argparse
|
|
18
|
-
import json
|
|
19
25
|
import re
|
|
20
26
|
import subprocess
|
|
21
27
|
import sys
|
|
@@ -30,6 +36,7 @@ from common.paths import (
|
|
|
30
36
|
get_workspace_dir,
|
|
31
37
|
)
|
|
32
38
|
from common.developer import ensure_developer
|
|
39
|
+
from common.git import run_git
|
|
33
40
|
from common.tasks import load_task
|
|
34
41
|
from common.config import (
|
|
35
42
|
get_packages,
|
|
@@ -139,6 +146,7 @@ def generate_session_content(
|
|
|
139
146
|
extra_content: str,
|
|
140
147
|
today: str,
|
|
141
148
|
package: str | None = None,
|
|
149
|
+
branch: str | None = None,
|
|
142
150
|
) -> str:
|
|
143
151
|
"""Generate session content."""
|
|
144
152
|
if commit and commit != "-":
|
|
@@ -151,13 +159,14 @@ def generate_session_content(
|
|
|
151
159
|
commit_table = "(No commits - planning session)"
|
|
152
160
|
|
|
153
161
|
package_line = f"\n**Package**: {package}" if package else ""
|
|
162
|
+
branch_line = f"\n**Branch**: `{branch}`" if branch else ""
|
|
154
163
|
|
|
155
164
|
return f"""
|
|
156
165
|
|
|
157
166
|
## Session {session_num}: {title}
|
|
158
167
|
|
|
159
168
|
**Date**: {today}
|
|
160
|
-
**Task**: {title}{package_line}
|
|
169
|
+
**Task**: {title}{package_line}{branch_line}
|
|
161
170
|
|
|
162
171
|
### Summary
|
|
163
172
|
|
|
@@ -192,7 +201,8 @@ def update_index(
|
|
|
192
201
|
commit: str,
|
|
193
202
|
new_session: int,
|
|
194
203
|
active_file: str,
|
|
195
|
-
today: str
|
|
204
|
+
today: str,
|
|
205
|
+
branch: str | None = None,
|
|
196
206
|
) -> bool:
|
|
197
207
|
"""Update index.md with new session info."""
|
|
198
208
|
# Format commit for display
|
|
@@ -271,10 +281,25 @@ def update_index(
|
|
|
271
281
|
continue
|
|
272
282
|
|
|
273
283
|
if in_session_history:
|
|
274
|
-
|
|
275
|
-
if re.match(
|
|
276
|
-
|
|
284
|
+
# Migrate old 4/6-column headers to 5-column Branch-only history.
|
|
285
|
+
if re.match(
|
|
286
|
+
r"^\|\s*#\s*\|\s*Date\s*\|\s*Title\s*\|\s*Commits\s*\|\s*Branch\s*\|\s*Base Branch\s*\|\s*$",
|
|
287
|
+
line,
|
|
288
|
+
):
|
|
289
|
+
new_lines.append("| # | Date | Title | Commits | Branch |")
|
|
290
|
+
continue
|
|
291
|
+
if re.match(r"^\|\s*#\s*\|\s*Date\s*\|\s*Title\s*\|\s*Commits\s*\|\s*Branch\s*\|\s*$", line):
|
|
292
|
+
new_lines.append("| # | Date | Title | Commits | Branch |")
|
|
293
|
+
continue
|
|
294
|
+
if re.match(r"^\|\s*#\s*\|\s*Date\s*\|\s*Title\s*\|\s*Commits\s*\|\s*$", line):
|
|
295
|
+
new_lines.append("| # | Date | Title | Commits | Branch |")
|
|
296
|
+
continue
|
|
297
|
+
if re.match(r"^\|[-| ]+\|\s*$", line) and not header_written:
|
|
298
|
+
new_lines.append("|---|------|-------|---------|--------|")
|
|
299
|
+
new_lines.append(f"| {new_session} | {today} | {title} | {commit_display} | `{branch or '-'}` |")
|
|
277
300
|
header_written = True
|
|
301
|
+
continue
|
|
302
|
+
new_lines.append(line)
|
|
278
303
|
continue
|
|
279
304
|
|
|
280
305
|
new_lines.append(line)
|
|
@@ -291,11 +316,16 @@ def update_index(
|
|
|
291
316
|
def _auto_commit_workspace(repo_root: Path) -> None:
|
|
292
317
|
"""Stage .trellis/workspace and .trellis/tasks, then commit with a configured message."""
|
|
293
318
|
commit_msg = get_session_commit_message(repo_root)
|
|
294
|
-
subprocess.run(
|
|
319
|
+
add_result = subprocess.run(
|
|
295
320
|
["git", "add", "-A", ".trellis/workspace", ".trellis/tasks"],
|
|
296
321
|
cwd=repo_root,
|
|
297
322
|
capture_output=True,
|
|
323
|
+
text=True,
|
|
298
324
|
)
|
|
325
|
+
if add_result.returncode != 0:
|
|
326
|
+
print(f"[WARN] git add failed (exit {add_result.returncode}): {add_result.stderr.strip()}", file=sys.stderr)
|
|
327
|
+
print("[WARN] Please commit .trellis/ changes manually: git add .trellis && git commit", file=sys.stderr)
|
|
328
|
+
return
|
|
299
329
|
# Check if there are staged changes
|
|
300
330
|
result = subprocess.run(
|
|
301
331
|
["git", "diff", "--cached", "--quiet", "--", ".trellis/workspace", ".trellis/tasks"],
|
|
@@ -323,6 +353,7 @@ def add_session(
|
|
|
323
353
|
extra_content: str = "(Add details)",
|
|
324
354
|
auto_commit: bool = True,
|
|
325
355
|
package: str | None = None,
|
|
356
|
+
branch: str | None = None,
|
|
326
357
|
) -> int:
|
|
327
358
|
"""Add a new session."""
|
|
328
359
|
repo_root = get_repo_root()
|
|
@@ -348,7 +379,8 @@ def add_session(
|
|
|
348
379
|
new_session = current_session + 1
|
|
349
380
|
|
|
350
381
|
session_content = generate_session_content(
|
|
351
|
-
new_session, title, commit, summary, extra_content, today, package
|
|
382
|
+
new_session, title, commit, summary, extra_content, today, package,
|
|
383
|
+
branch,
|
|
352
384
|
)
|
|
353
385
|
content_lines = len(session_content.splitlines())
|
|
354
386
|
|
|
@@ -385,7 +417,16 @@ def add_session(
|
|
|
385
417
|
|
|
386
418
|
# Update index.md
|
|
387
419
|
active_file = f"{FILE_JOURNAL_PREFIX}{target_num}.md"
|
|
388
|
-
if not update_index(
|
|
420
|
+
if not update_index(
|
|
421
|
+
index_file,
|
|
422
|
+
dev_dir,
|
|
423
|
+
title,
|
|
424
|
+
commit,
|
|
425
|
+
new_session,
|
|
426
|
+
active_file,
|
|
427
|
+
today,
|
|
428
|
+
branch,
|
|
429
|
+
):
|
|
389
430
|
return 1
|
|
390
431
|
|
|
391
432
|
print("", file=sys.stderr)
|
|
@@ -419,6 +460,7 @@ def main() -> int:
|
|
|
419
460
|
parser.add_argument("--summary", default="(Add summary)", help="Brief summary")
|
|
420
461
|
parser.add_argument("--content-file", help="Path to file with detailed content")
|
|
421
462
|
parser.add_argument("--package", help="Package name tag (e.g., cli, docs-site)")
|
|
463
|
+
parser.add_argument("--branch", help="Branch name (auto-detected if omitted)")
|
|
422
464
|
parser.add_argument("--no-commit", action="store_true",
|
|
423
465
|
help="Skip auto-commit of workspace changes")
|
|
424
466
|
parser.add_argument("--stdin", action="store_true",
|
|
@@ -434,8 +476,11 @@ def main() -> int:
|
|
|
434
476
|
elif args.stdin:
|
|
435
477
|
extra_content = sys.stdin.read()
|
|
436
478
|
|
|
437
|
-
#
|
|
479
|
+
# Load active task once — shared by package and branch resolution
|
|
438
480
|
repo_root = get_repo_root()
|
|
481
|
+
current = get_current_task(repo_root)
|
|
482
|
+
task_data = load_task(repo_root / current) if current else None
|
|
483
|
+
|
|
439
484
|
package = args.package
|
|
440
485
|
if package:
|
|
441
486
|
# CLI source: fail-fast in monorepo, ignore in single-repo
|
|
@@ -449,18 +494,26 @@ def main() -> int:
|
|
|
449
494
|
return 1
|
|
450
495
|
else:
|
|
451
496
|
# Inferred: active task's task.json.package → default_package → None
|
|
452
|
-
task_package = None
|
|
453
|
-
current = get_current_task(repo_root)
|
|
454
|
-
if current:
|
|
455
|
-
ct = load_task(repo_root / current)
|
|
456
|
-
if ct and ct.package:
|
|
457
|
-
task_package = ct.package
|
|
497
|
+
task_package = task_data.package if task_data else None
|
|
458
498
|
package = resolve_package(task_package, repo_root)
|
|
459
499
|
|
|
500
|
+
# Resolve branch: CLI → task.json → git auto-detect → None
|
|
501
|
+
branch = args.branch
|
|
502
|
+
|
|
503
|
+
if not branch:
|
|
504
|
+
if task_data and task_data.raw.get("branch"):
|
|
505
|
+
branch = task_data.raw["branch"]
|
|
506
|
+
else:
|
|
507
|
+
_, branch_out, _ = run_git(["branch", "--show-current"], cwd=repo_root)
|
|
508
|
+
detected = branch_out.strip()
|
|
509
|
+
if detected:
|
|
510
|
+
branch = detected
|
|
511
|
+
|
|
460
512
|
return add_session(
|
|
461
513
|
args.title, args.commit, args.summary, extra_content,
|
|
462
514
|
auto_commit=not args.no_commit,
|
|
463
515
|
package=package,
|
|
516
|
+
branch=branch,
|
|
464
517
|
)
|
|
465
518
|
|
|
466
519
|
|