@mindfoldhq/trellis 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/index.js +11 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +5 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +49 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mem.d.ts.map +1 -1
- package/dist/commands/mem.js +4 -3
- package/dist/commands/mem.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +1 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/antigravity.d.ts +1 -1
- package/dist/configurators/antigravity.js +1 -1
- package/dist/configurators/claude.d.ts +5 -2
- package/dist/configurators/claude.d.ts.map +1 -1
- package/dist/configurators/claude.js +37 -4
- package/dist/configurators/claude.js.map +1 -1
- package/dist/configurators/codebuddy.d.ts +1 -1
- package/dist/configurators/codebuddy.js +1 -1
- package/dist/configurators/codex.js +2 -2
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/copilot.d.ts +1 -1
- package/dist/configurators/copilot.js +1 -1
- package/dist/configurators/cursor.d.ts +1 -1
- package/dist/configurators/cursor.js +1 -1
- package/dist/configurators/devin.d.ts +7 -0
- package/dist/configurators/devin.d.ts.map +1 -0
- package/dist/configurators/{windsurf.js → devin.js} +7 -7
- package/dist/configurators/devin.js.map +1 -0
- package/dist/configurators/droid.d.ts +1 -1
- package/dist/configurators/droid.js +1 -1
- package/dist/configurators/gemini.d.ts +1 -1
- package/dist/configurators/gemini.js +1 -1
- package/dist/configurators/index.d.ts +2 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +17 -6
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/kilo.d.ts +1 -1
- package/dist/configurators/kilo.js +1 -1
- package/dist/configurators/shared.d.ts +18 -5
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +8 -8
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/zcode.d.ts +19 -0
- package/dist/configurators/zcode.d.ts.map +1 -0
- package/dist/configurators/zcode.js +54 -0
- package/dist/configurators/zcode.js.map +1 -0
- package/dist/migrations/manifests/0.6.2.json +9 -0
- package/dist/migrations/manifests/0.6.3.json +24 -0
- package/dist/templates/claude/hooks/statusline.py +324 -0
- package/dist/templates/claude/index.d.ts +10 -1
- package/dist/templates/claude/index.d.ts.map +1 -1
- package/dist/templates/claude/index.js +12 -1
- package/dist/templates/claude/index.js.map +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +4 -4
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +2 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +2 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +3 -3
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +3 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +2 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +4 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +3 -1
- package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-session-insight/references/cli-quick-reference.md +23 -24
- package/dist/templates/common/commands/continue.md +1 -1
- package/dist/templates/common/skills/brainstorm.md +43 -0
- package/dist/templates/common/skills/break-loop.md +59 -0
- package/dist/templates/shared-hooks/index.d.ts +4 -2
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +4 -2
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +26 -6
- package/dist/templates/trellis/scripts/common/cli_adapter.py +46 -32
- package/dist/templates/trellis/scripts/common/safe_commit.py +46 -16
- package/dist/templates/trellis/scripts/common/task_store.py +2 -2
- package/dist/templates/trellis/scripts/common/workflow_phase.py +1 -1
- package/dist/templates/trellis/workflow.md +10 -10
- package/dist/templates/zcode/agents/trellis-check.md +102 -0
- package/dist/templates/zcode/agents/trellis-implement.md +102 -0
- package/dist/templates/zcode/index.d.ts +15 -0
- package/dist/templates/zcode/index.d.ts.map +1 -0
- package/dist/templates/zcode/index.js +18 -0
- package/dist/templates/zcode/index.js.map +1 -0
- package/dist/types/ai-tools.d.ts +4 -4
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +25 -7
- package/dist/types/ai-tools.js.map +1 -1
- package/package.json +2 -2
- package/dist/configurators/windsurf.d.ts +0 -7
- package/dist/configurators/windsurf.d.ts.map +0 -1
- package/dist/configurators/windsurf.js.map +0 -1
|
@@ -4,32 +4,31 @@ Full flag reference for the five subcommands. Pin this as the authoritative sour
|
|
|
4
4
|
|
|
5
5
|
## Subcommands
|
|
6
6
|
|
|
7
|
-
| Command
|
|
8
|
-
|
|
9
|
-
| `list`
|
|
10
|
-
| `search <keyword>`
|
|
11
|
-
| `context <session-id>` | Drill into one session: top-N hit turns + surrounding context. Pair with `--grep` for keyword anchoring.
|
|
12
|
-
| `extract <session-id>` | Dump cleaned dialogue. Combine with `--phase` / `--grep` to slice.
|
|
13
|
-
| `projects`
|
|
7
|
+
| Command | Purpose |
|
|
8
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
9
|
+
| `list` | List sessions. Default subcommand when none is given. |
|
|
10
|
+
| `search <keyword>` | Find sessions whose contents match a keyword. |
|
|
11
|
+
| `context <session-id>` | Drill into one session: top-N hit turns + surrounding context. Pair with `--grep` for keyword anchoring. |
|
|
12
|
+
| `extract <session-id>` | Dump cleaned dialogue. Combine with `--phase` / `--grep` to slice. |
|
|
13
|
+
| `projects` | List active project `cwd` values with session counts. Use this to discover which `--cwd` to pass to other subcommands. |
|
|
14
14
|
|
|
15
15
|
## Flags (apply where meaningful)
|
|
16
16
|
|
|
17
|
-
| Flag
|
|
18
|
-
|
|
19
|
-
| `--platform claude\|codex\|opencode\|all` | all
|
|
20
|
-
| `--since YYYY-MM-DD`
|
|
21
|
-
| `--until YYYY-MM-DD`
|
|
22
|
-
| `--global`
|
|
23
|
-
| `--cwd <path>`
|
|
24
|
-
| `--limit N`
|
|
25
|
-
| `--grep KW`
|
|
26
|
-
| `--phase brainstorm\|implement\|all`
|
|
27
|
-
| `--turns N`
|
|
28
|
-
| `--around N`
|
|
29
|
-
| `--max-chars N`
|
|
30
|
-
| `--include-children`
|
|
31
|
-
| `--json`
|
|
32
|
-
| `--task <task-dir>` | list | Narrow to sessions whose context-key resolved to a given task directory (uses `.trellis/.runtime/sessions/*.json`). |
|
|
17
|
+
| Flag | Subcommands | Meaning |
|
|
18
|
+
| --------------------------------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `--platform claude\|codex\|opencode\|pi\|all` | all | Default `all`. OpenCode adapter is currently a stub on `0.6.0-beta.*` — see "Caveats" below. |
|
|
20
|
+
| `--since YYYY-MM-DD` | list / search | Inclusive lower date bound. |
|
|
21
|
+
| `--until YYYY-MM-DD` | list / search | Inclusive upper date bound. |
|
|
22
|
+
| `--global` | list / search | Include sessions from every project on this machine. Default is the current project `cwd`. |
|
|
23
|
+
| `--cwd <path>` | list / search | Force a specific project cwd instead of inferring from where you are. |
|
|
24
|
+
| `--limit N` | list / search | Cap output rows. Default `50`. |
|
|
25
|
+
| `--grep KW` | extract / context | Filter turns by keyword. Multi-token AND when whitespace-separated. |
|
|
26
|
+
| `--phase brainstorm\|implement\|all` | extract | Slice session by Trellis task boundaries. `brainstorm` = `[task.py create, task.py start)`. `implement` = turns outside brainstorm windows. Default `all`. |
|
|
27
|
+
| `--turns N` | context | Number of hit turns to return. Default `3`. |
|
|
28
|
+
| `--around N` | context | Surrounding turns to include per hit. Default `1`. |
|
|
29
|
+
| `--max-chars N` | context | Total character budget. Default `6000` (~1500 tokens). |
|
|
30
|
+
| `--include-children` | search / context | Merge OpenCode sub-agent sessions into their parent session. |
|
|
31
|
+
| `--json` | all | Emit machine-parseable JSON instead of human-readable output. |
|
|
33
32
|
|
|
34
33
|
## Common one-liners
|
|
35
34
|
|
|
@@ -58,7 +57,7 @@ trellis mem projects
|
|
|
58
57
|
|
|
59
58
|
- **OpenCode adapter is a stub on `0.6.0-beta.*`.** When `--platform` resolves to OpenCode (or `all` and OpenCode would be included), `mem` prints a one-line "reader unavailable" notice and continues with the other platforms. Don't promise OpenCode coverage in your reply until the adapter ships.
|
|
60
59
|
- **`--phase` slicing depends on `task.py create` / `task.py start` invocations appearing in the recorded bash calls of the session.** Sessions where the user ran `task.py` from a different terminal — outside the recorded AI loop — will not have phase boundaries. `--phase all` is the safe fallback.
|
|
61
|
-
- **`mem` indexes platform JSONL files directly.** If the user has cleared their Claude / Codex session storage, `mem` cannot recover what is no longer on disk.
|
|
60
|
+
- **`mem` indexes platform JSONL files directly.** If the user has cleared their Claude / Codex / Pi session storage, `mem` cannot recover what is no longer on disk.
|
|
62
61
|
- **`mem` is read-only.** No remote sync, no edits to platform JSONL. Any write you do based on `mem` findings is your own follow-up call into the editing tools available to you.
|
|
63
62
|
|
|
64
63
|
## When you need more than this reference
|
|
@@ -30,7 +30,7 @@ Shows the Phase Index (Plan / Execute / Finish) with routing + skill mapping.
|
|
|
30
30
|
- `status=planning` + required artifacts complete + required jsonl curated or inline mode → **1.4** (ask for start review; only run `task.py start` after user confirms)
|
|
31
31
|
- `status=in_progress` + implementation not started → **2.1**
|
|
32
32
|
- `status=in_progress` + implementation done, not yet checked → **2.2**
|
|
33
|
-
- `status=in_progress` + check passed → **3.
|
|
33
|
+
- `status=in_progress` + check passed → **3.3** (spec update) → **3.4** (commit)
|
|
34
34
|
- `status=completed` (rare; usually archived immediately) → archive flow
|
|
35
35
|
|
|
36
36
|
Phase rules (full detail in `.trellis/workflow.md`):
|
|
@@ -64,6 +64,49 @@ Each question must include:
|
|
|
64
64
|
|
|
65
65
|
Do not ask process questions such as whether to search, inspect files, or continue brainstorming. Do the evidence work directly. Ask the user only when the remaining issue is a product decision, preference, scope boundary, or risk tolerance choice.
|
|
66
66
|
|
|
67
|
+
## Thinking Framework: First Principles Analysis
|
|
68
|
+
|
|
69
|
+
When requirements are vague, solutions feel over-engineered, or you're about to add complexity "because everyone does" — decompose to fundamental truths before reasoning upward.
|
|
70
|
+
|
|
71
|
+
### Step 1: Restate the Problem
|
|
72
|
+
|
|
73
|
+
Strip away implementation details to one sentence.
|
|
74
|
+
|
|
75
|
+
> Bad: "We need to add Redis caching to the user profile endpoint"
|
|
76
|
+
> Good: "User profile data takes too long to load"
|
|
77
|
+
|
|
78
|
+
### Step 2: List Fundamental Truths
|
|
79
|
+
|
|
80
|
+
What is absolutely true (not opinion or convention)?
|
|
81
|
+
|
|
82
|
+
| Category | Examples |
|
|
83
|
+
|----------|----------|
|
|
84
|
+
| **Physical constraints** | Network latency ≥ 0, disk I/O has limits |
|
|
85
|
+
| **Business rules** | "Users must see their own data" |
|
|
86
|
+
| **Technical invariants** | "Data must be consistent" |
|
|
87
|
+
| **User needs** | "The user wants X within Y seconds" |
|
|
88
|
+
|
|
89
|
+
### Step 3: Challenge Assumptions
|
|
90
|
+
|
|
91
|
+
For each component of the current plan:
|
|
92
|
+
|
|
93
|
+
- **Fact or convention?** "We always use REST" — why?
|
|
94
|
+
- **What if we removed this?** If nothing breaks, it's unnecessary.
|
|
95
|
+
- **Solving the actual problem or a symptom?** Trace the causal chain.
|
|
96
|
+
- **Who benefits from this complexity?** If "nobody", simplify.
|
|
97
|
+
|
|
98
|
+
### Step 4: Build Up from Truths
|
|
99
|
+
|
|
100
|
+
1. Start with the minimum viable mechanism satisfying all truths
|
|
101
|
+
2. Add complexity only when a specific truth demands it
|
|
102
|
+
3. Each addition must answer: "Which truth requires this?"
|
|
103
|
+
|
|
104
|
+
### Step 5: Validate
|
|
105
|
+
|
|
106
|
+
- Does the solution solve the original problem?
|
|
107
|
+
- What assumptions need verification?
|
|
108
|
+
- What's the simplest experiment to test this?
|
|
109
|
+
|
|
67
110
|
## Artifact Rules
|
|
68
111
|
|
|
69
112
|
`prd.md` records requirements and acceptance:
|
|
@@ -106,6 +106,65 @@ Three levels of insight:
|
|
|
106
106
|
|
|
107
107
|
30 minutes of analysis saves 30 hours of future debugging.
|
|
108
108
|
|
|
109
|
+
|
|
110
|
+
## Thinking Framework: Bayesian Reasoning
|
|
111
|
+
|
|
112
|
+
When multiple root causes are plausible and evidence is incomplete, update your beliefs proportionally to new evidence rather than clinging to initial assumptions.
|
|
113
|
+
|
|
114
|
+
### Step 1: Establish Priors
|
|
115
|
+
|
|
116
|
+
Before investigating, state what you believe and why:
|
|
117
|
+
|
|
118
|
+
| Hypothesis | Prior | Reasoning |
|
|
119
|
+
|------------|-------|-----------|
|
|
120
|
+
| H1: [cause A] | 40% | Most common for this pattern |
|
|
121
|
+
| H2: [cause B] | 30% | Plausible given environment |
|
|
122
|
+
| H3: [other] | 30% | Catch-all |
|
|
123
|
+
|
|
124
|
+
Priors must sum to 100%. If you can't assign probabilities, investigate first.
|
|
125
|
+
|
|
126
|
+
### Step 2: Observe Evidence
|
|
127
|
+
|
|
128
|
+
Document what you found — be specific about reliability:
|
|
129
|
+
|
|
130
|
+
- What exactly did you observe?
|
|
131
|
+
- How reliable? (test output > log message > user report > hunch)
|
|
132
|
+
- Could multiple hypotheses explain this?
|
|
133
|
+
|
|
134
|
+
### Step 3: Update Beliefs
|
|
135
|
+
|
|
136
|
+
For each hypothesis, ask: **How likely is this evidence if this hypothesis were true?**
|
|
137
|
+
|
|
138
|
+
Direction of update matters more than calculation:
|
|
139
|
+
- Evidence strongly predicted by H1 → H1 probability increases
|
|
140
|
+
- Evidence contradicts H2 → H2 probability decreases
|
|
141
|
+
- Evidence equally likely under all → no update
|
|
142
|
+
|
|
143
|
+
### Step 4: Seek Discriminating Evidence
|
|
144
|
+
|
|
145
|
+
Don't gather more of the same. Find evidence that **differs strongly** between top hypotheses.
|
|
146
|
+
|
|
147
|
+
> If H1 and H3 are close: "What would I see if H1 is true but not if H3 is true?" Then check for that.
|
|
148
|
+
|
|
149
|
+
### Step 5: State Confidence
|
|
150
|
+
|
|
151
|
+
| Confidence | Action |
|
|
152
|
+
|------------|--------|
|
|
153
|
+
| 90%+ | Proceed with fix, monitor |
|
|
154
|
+
| 70-90% | Proceed, add fallback check |
|
|
155
|
+
| 50-70% | Test hypothesis before committing |
|
|
156
|
+
| <50% | Need more evidence, don't guess |
|
|
157
|
+
|
|
158
|
+
Never express binary certainty when evidence is incomplete. Use "most likely", "plausible but unlikely", "worth investigating".
|
|
159
|
+
|
|
160
|
+
### Common Fallacies
|
|
161
|
+
|
|
162
|
+
| Fallacy | Example | Correction |
|
|
163
|
+
|---------|---------|------------|
|
|
164
|
+
| **Base rate neglect** | "Test failed → code is broken" | How often do tests fail for other reasons? |
|
|
165
|
+
| **Confirmation bias** | "Must be a race condition, let me find race evidence" | Actively seek evidence AGAINST your top hypothesis |
|
|
166
|
+
| **Anchoring** | "Last time it was caching, probably caching again" | Establish priors from current context, not yesterday's bug |
|
|
167
|
+
|
|
109
168
|
---
|
|
110
169
|
|
|
111
170
|
## After Analysis: Immediate Actions
|
|
@@ -32,8 +32,10 @@ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qod
|
|
|
32
32
|
* - Kiro supports only `agentSpawn` (no SessionStart / UserPromptSubmit
|
|
33
33
|
* event), so it takes just `inject-subagent-context.py`.
|
|
34
34
|
* - Claude Code `statusLine` is intentionally not installed by default.
|
|
35
|
-
* Users can add their own statusLine command in `.claude/settings.json
|
|
36
|
-
*
|
|
35
|
+
* Users can add their own statusLine command in `.claude/settings.json`,
|
|
36
|
+
* or opt in to the Trellis one via `trellis init --with-statusline`
|
|
37
|
+
* (installed from `templates/claude/hooks/`, not from this table — no
|
|
38
|
+
* other platform has a statusLine event).
|
|
37
39
|
*/
|
|
38
40
|
export declare const SHARED_HOOKS_BY_PLATFORM: Record<SharedHookPlatform, readonly SharedHookName[]>;
|
|
39
41
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,CAAC;AAEX
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CA2B1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CAGd"}
|
|
@@ -32,8 +32,10 @@ function readTemplate(relativePath) {
|
|
|
32
32
|
* - Kiro supports only `agentSpawn` (no SessionStart / UserPromptSubmit
|
|
33
33
|
* event), so it takes just `inject-subagent-context.py`.
|
|
34
34
|
* - Claude Code `statusLine` is intentionally not installed by default.
|
|
35
|
-
* Users can add their own statusLine command in `.claude/settings.json
|
|
36
|
-
*
|
|
35
|
+
* Users can add their own statusLine command in `.claude/settings.json`,
|
|
36
|
+
* or opt in to the Trellis one via `trellis init --with-statusline`
|
|
37
|
+
* (installed from `templates/claude/hooks/`, not from this table — no
|
|
38
|
+
* other platform has a statusLine event).
|
|
37
39
|
*/
|
|
38
40
|
export const SHARED_HOOKS_BY_PLATFORM = {
|
|
39
41
|
claude: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AA0BD
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,SAAS,YAAY,CAAC,YAAoB;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC;AAC9D,CAAC;AA0BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAGjC;IACF,MAAM,EAAE;QACN,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,MAAM,EAAE;QACN,kBAAkB;QAClB,iCAAiC;QACjC,4BAA4B;KAC7B;IACD,KAAK,EAAE,CAAC,0BAA0B,CAAC;IACnC,MAAM,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACxD,KAAK,EAAE,CAAC,kBAAkB,EAAE,0BAA0B,CAAC;IACvD,OAAO,EAAE,CAAC,0BAA0B,CAAC;IACrC,SAAS,EAAE;QACT,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,KAAK,EAAE;QACL,kBAAkB;QAClB,0BAA0B;QAC1B,4BAA4B;KAC7B;IACD,IAAI,EAAE,CAAC,4BAA4B,CAAC;CACrC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,WAAW,CAAC,SAAS,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAChC,IAAI,EAAE,CAAC;IAEV,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC7C,QAA4B;IAE5B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,wBAAwB,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC"}
|
|
@@ -28,6 +28,8 @@ from datetime import datetime
|
|
|
28
28
|
from pathlib import Path
|
|
29
29
|
|
|
30
30
|
from common.paths import (
|
|
31
|
+
DIR_TASKS,
|
|
32
|
+
DIR_WORKFLOW,
|
|
31
33
|
FILE_JOURNAL_PREFIX,
|
|
32
34
|
get_repo_root,
|
|
33
35
|
get_current_task,
|
|
@@ -319,12 +321,14 @@ def update_index(
|
|
|
319
321
|
# =============================================================================
|
|
320
322
|
|
|
321
323
|
def _auto_commit_workspace(repo_root: Path) -> None:
|
|
322
|
-
"""Stage Trellis-owned workspace + task paths and commit.
|
|
324
|
+
"""Stage Trellis-owned workspace + current-task paths and commit.
|
|
323
325
|
|
|
324
|
-
Path scope is restricted to specific products
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
Path scope is restricted to specific products: the current developer's
|
|
327
|
+
journal files + index.md, and ONLY the current task directory (resolved
|
|
328
|
+
via ``get_current_task``). We never `git add` the whole `.trellis/` tree
|
|
329
|
+
or iterate over all active task dirs (#303: parallel-window dirty task
|
|
330
|
+
dirs must not be bundled into the session auto-commit). If `.gitignore`
|
|
331
|
+
blocks the specific paths we warn + skip — never retry with ``-f``.
|
|
328
332
|
|
|
329
333
|
Honors ``session_auto_commit`` in ``.trellis/config.yaml``: when set to
|
|
330
334
|
``false``, this function returns immediately without touching git
|
|
@@ -338,7 +342,23 @@ def _auto_commit_workspace(repo_root: Path) -> None:
|
|
|
338
342
|
return
|
|
339
343
|
|
|
340
344
|
commit_msg = get_session_commit_message(repo_root)
|
|
341
|
-
|
|
345
|
+
# Resolve the current task so staging is scoped to its dir only. The ref
|
|
346
|
+
# is ``.trellis/tasks/<name>`` (or under archive/) — pass the bare name.
|
|
347
|
+
current = get_current_task(repo_root)
|
|
348
|
+
if current:
|
|
349
|
+
task_name = Path(current).name
|
|
350
|
+
paths = safe_trellis_paths_to_add(repo_root, task_name=task_name)
|
|
351
|
+
else:
|
|
352
|
+
# Current task unknown (0 or >=2 parallel sessions — exactly the
|
|
353
|
+
# parallel-window case #303 is about). Do NOT fall back to the wide
|
|
354
|
+
# `tasks_dir.iterdir()` scan; that would re-leak other tasks' dirty
|
|
355
|
+
# dirs into the session commit. Stage only the developer's journal/
|
|
356
|
+
# index and skip every task dir.
|
|
357
|
+
paths = [
|
|
358
|
+
p
|
|
359
|
+
for p in safe_trellis_paths_to_add(repo_root, task_name=None)
|
|
360
|
+
if not p.startswith(f"{DIR_WORKFLOW}/{DIR_TASKS}/")
|
|
361
|
+
]
|
|
342
362
|
if not paths:
|
|
343
363
|
print("[OK] No workspace changes to commit.", file=sys.stderr)
|
|
344
364
|
return
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
CLI Adapter for Multi-Platform Support.
|
|
3
3
|
|
|
4
|
-
Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity,
|
|
4
|
+
Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity, Devin, Qoder, CodeBuddy, GitHub Copilot, Factory Droid, and Pi Agent interfaces.
|
|
5
5
|
|
|
6
6
|
Supported platforms:
|
|
7
7
|
- claude: Claude Code (default)
|
|
@@ -13,7 +13,7 @@ Supported platforms:
|
|
|
13
13
|
- kiro: Kiro Code (skills-based)
|
|
14
14
|
- gemini: Gemini CLI
|
|
15
15
|
- antigravity: Antigravity (workflow-based)
|
|
16
|
-
-
|
|
16
|
+
- devin: Devin (formerly Windsurf; workflow-based)
|
|
17
17
|
- qoder: Qoder
|
|
18
18
|
- codebuddy: CodeBuddy
|
|
19
19
|
- copilot: GitHub Copilot (VS Code)
|
|
@@ -47,7 +47,7 @@ Platform = Literal[
|
|
|
47
47
|
"kiro",
|
|
48
48
|
"gemini",
|
|
49
49
|
"antigravity",
|
|
50
|
-
"
|
|
50
|
+
"devin",
|
|
51
51
|
"qoder",
|
|
52
52
|
"codebuddy",
|
|
53
53
|
"copilot",
|
|
@@ -97,7 +97,7 @@ class CLIAdapter:
|
|
|
97
97
|
"""Get platform-specific config directory name.
|
|
98
98
|
|
|
99
99
|
Returns:
|
|
100
|
-
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.
|
|
100
|
+
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.devin', '.qoder', '.codebuddy', '.github/copilot', '.factory', or '.pi')
|
|
101
101
|
"""
|
|
102
102
|
if self.platform == "opencode":
|
|
103
103
|
return ".opencode"
|
|
@@ -115,8 +115,8 @@ class CLIAdapter:
|
|
|
115
115
|
return ".gemini"
|
|
116
116
|
elif self.platform == "antigravity":
|
|
117
117
|
return ".agent"
|
|
118
|
-
elif self.platform == "
|
|
119
|
-
return ".
|
|
118
|
+
elif self.platform == "devin":
|
|
119
|
+
return ".devin"
|
|
120
120
|
elif self.platform == "qoder":
|
|
121
121
|
return ".qoder"
|
|
122
122
|
elif self.platform == "codebuddy":
|
|
@@ -137,7 +137,7 @@ class CLIAdapter:
|
|
|
137
137
|
project_root: Project root directory
|
|
138
138
|
|
|
139
139
|
Returns:
|
|
140
|
-
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .
|
|
140
|
+
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .devin, .qoder, .codebuddy, .github/copilot, .factory, or .pi)
|
|
141
141
|
"""
|
|
142
142
|
return project_root / self.config_dir_name
|
|
143
143
|
|
|
@@ -169,7 +169,7 @@ class CLIAdapter:
|
|
|
169
169
|
Note:
|
|
170
170
|
Cursor uses prefix naming: .cursor/commands/trellis-<name>.md
|
|
171
171
|
Antigravity uses workflow directory: .agent/workflows/<name>.md
|
|
172
|
-
|
|
172
|
+
Devin uses workflow directory: .devin/workflows/trellis-<name>.md
|
|
173
173
|
Copilot uses prompt files: .github/prompts/<name>.prompt.md
|
|
174
174
|
Pi uses prompt templates: .pi/prompts/trellis-<name>.md
|
|
175
175
|
Claude/OpenCode use subdirectory: .claude/commands/trellis/<name>.md
|
|
@@ -185,7 +185,7 @@ class CLIAdapter:
|
|
|
185
185
|
return prompts_dir / f"trellis-{filename}.md"
|
|
186
186
|
return prompts_dir / Path(*parts)
|
|
187
187
|
|
|
188
|
-
if self.platform == "
|
|
188
|
+
if self.platform == "devin":
|
|
189
189
|
workflow_dir = self.get_config_dir(project_root) / "workflows"
|
|
190
190
|
if not parts:
|
|
191
191
|
return workflow_dir
|
|
@@ -242,7 +242,7 @@ class CLIAdapter:
|
|
|
242
242
|
Kiro: .kiro/skills/trellis-<name>/SKILL.md
|
|
243
243
|
Gemini: .gemini/commands/trellis/<name>.toml
|
|
244
244
|
Antigravity: .agent/workflows/<name>.md
|
|
245
|
-
|
|
245
|
+
Devin: .devin/workflows/trellis-<name>.md
|
|
246
246
|
Pi: .pi/prompts/trellis-<name>.md
|
|
247
247
|
Others: .{platform}/commands/trellis/<name>.md
|
|
248
248
|
"""
|
|
@@ -258,8 +258,8 @@ class CLIAdapter:
|
|
|
258
258
|
return f".gemini/commands/trellis/{name}.toml"
|
|
259
259
|
elif self.platform == "antigravity":
|
|
260
260
|
return f".agent/workflows/{name}.md"
|
|
261
|
-
elif self.platform == "
|
|
262
|
-
return f".
|
|
261
|
+
elif self.platform == "devin":
|
|
262
|
+
return f".devin/workflows/trellis-{name}.md"
|
|
263
263
|
elif self.platform == "kilo":
|
|
264
264
|
return f".kilocode/workflows/{name}.md"
|
|
265
265
|
elif self.platform == "copilot":
|
|
@@ -293,7 +293,7 @@ class CLIAdapter:
|
|
|
293
293
|
return {} # Gemini CLI doesn't have a non-interactive env var
|
|
294
294
|
elif self.platform == "antigravity":
|
|
295
295
|
return {}
|
|
296
|
-
elif self.platform == "
|
|
296
|
+
elif self.platform == "devin":
|
|
297
297
|
return {}
|
|
298
298
|
elif self.platform == "qoder":
|
|
299
299
|
return {}
|
|
@@ -370,9 +370,9 @@ class CLIAdapter:
|
|
|
370
370
|
raise ValueError(
|
|
371
371
|
"Antigravity workflows are UI slash commands; CLI agent run is not supported."
|
|
372
372
|
)
|
|
373
|
-
elif self.platform == "
|
|
373
|
+
elif self.platform == "devin":
|
|
374
374
|
raise ValueError(
|
|
375
|
-
"
|
|
375
|
+
"Devin workflows are UI slash commands; CLI agent run is not supported."
|
|
376
376
|
)
|
|
377
377
|
elif self.platform == "qoder":
|
|
378
378
|
cmd = ["qodercli", "-p", prompt]
|
|
@@ -436,9 +436,9 @@ class CLIAdapter:
|
|
|
436
436
|
raise ValueError(
|
|
437
437
|
"Antigravity workflows are UI slash commands; CLI resume is not supported."
|
|
438
438
|
)
|
|
439
|
-
elif self.platform == "
|
|
439
|
+
elif self.platform == "devin":
|
|
440
440
|
raise ValueError(
|
|
441
|
-
"
|
|
441
|
+
"Devin workflows are UI slash commands; CLI resume is not supported."
|
|
442
442
|
)
|
|
443
443
|
elif self.platform == "qoder":
|
|
444
444
|
return ["qodercli", "--resume", session_id]
|
|
@@ -518,8 +518,8 @@ class CLIAdapter:
|
|
|
518
518
|
return "gemini"
|
|
519
519
|
elif self.platform == "antigravity":
|
|
520
520
|
return "agy"
|
|
521
|
-
elif self.platform == "
|
|
522
|
-
return "
|
|
521
|
+
elif self.platform == "devin":
|
|
522
|
+
return "devin"
|
|
523
523
|
elif self.platform == "qoder":
|
|
524
524
|
return "qodercli"
|
|
525
525
|
elif self.platform == "codebuddy":
|
|
@@ -594,14 +594,21 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
594
594
|
"""Get CLI adapter for the specified platform.
|
|
595
595
|
|
|
596
596
|
Args:
|
|
597
|
-
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', '
|
|
597
|
+
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', or 'pi')
|
|
598
598
|
|
|
599
599
|
Returns:
|
|
600
600
|
CLIAdapter instance
|
|
601
601
|
|
|
602
602
|
Raises:
|
|
603
603
|
ValueError: If platform is not supported
|
|
604
|
+
|
|
605
|
+
Note:
|
|
606
|
+
'windsurf' is accepted as a deprecated alias for 'devin' (Windsurf was
|
|
607
|
+
renamed to Devin) and normalized before validation.
|
|
604
608
|
"""
|
|
609
|
+
# Deprecated alias: Windsurf was renamed to Devin.
|
|
610
|
+
if platform == "windsurf":
|
|
611
|
+
platform = "devin"
|
|
605
612
|
if platform not in (
|
|
606
613
|
"claude",
|
|
607
614
|
"opencode",
|
|
@@ -612,7 +619,7 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
612
619
|
"kiro",
|
|
613
620
|
"gemini",
|
|
614
621
|
"antigravity",
|
|
615
|
-
"
|
|
622
|
+
"devin",
|
|
616
623
|
"qoder",
|
|
617
624
|
"codebuddy",
|
|
618
625
|
"copilot",
|
|
@@ -620,7 +627,7 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
620
627
|
"pi",
|
|
621
628
|
):
|
|
622
629
|
raise ValueError(
|
|
623
|
-
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', '
|
|
630
|
+
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', or 'pi')"
|
|
624
631
|
)
|
|
625
632
|
|
|
626
633
|
return CLIAdapter(platform=platform) # type: ignore
|
|
@@ -636,7 +643,8 @@ _ALL_PLATFORM_CONFIG_DIRS = (
|
|
|
636
643
|
".kiro",
|
|
637
644
|
".gemini",
|
|
638
645
|
".agent",
|
|
639
|
-
".
|
|
646
|
+
".devin",
|
|
647
|
+
".windsurf", # deprecated: pre-rename Devin config dir (still a platform signal)
|
|
640
648
|
".qoder",
|
|
641
649
|
".codebuddy",
|
|
642
650
|
".github/copilot",
|
|
@@ -647,7 +655,7 @@ _ALL_PLATFORM_CONFIG_DIRS = (
|
|
|
647
655
|
checks. `.agents/skills/` is NOT listed here: it is a shared cross-platform
|
|
648
656
|
layer (written by Codex, also consumed by Amp/Cline/Warp/etc. via the
|
|
649
657
|
agentskills.io standard), not a single-platform signal. Its presence must not
|
|
650
|
-
block detection of Kiro, Antigravity,
|
|
658
|
+
block detection of Kiro, Antigravity, Devin, or other platforms."""
|
|
651
659
|
|
|
652
660
|
|
|
653
661
|
def _has_other_platform_dir(project_root: Path, exclude: set[str]) -> bool:
|
|
@@ -672,7 +680,7 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
672
680
|
7. .kiro/skills exists and no other platform dirs → kiro
|
|
673
681
|
8. .gemini directory exists → gemini
|
|
674
682
|
9. .agent/workflows exists and no other platform dirs → antigravity
|
|
675
|
-
10. .windsurf/workflows exists and no other platform dirs →
|
|
683
|
+
10. .devin/workflows (or legacy .windsurf/workflows) exists and no other platform dirs → devin
|
|
676
684
|
11. .codebuddy directory exists → codebuddy
|
|
677
685
|
12. .qoder directory exists → qoder
|
|
678
686
|
13. .pi directory exists → pi
|
|
@@ -682,12 +690,15 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
682
690
|
project_root: Project root directory
|
|
683
691
|
|
|
684
692
|
Returns:
|
|
685
|
-
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', '
|
|
693
|
+
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', or default 'claude')
|
|
686
694
|
"""
|
|
687
695
|
import os
|
|
688
696
|
|
|
689
697
|
# Check environment variable first
|
|
690
698
|
env_platform = os.environ.get("TRELLIS_PLATFORM", "").lower()
|
|
699
|
+
# Deprecated alias: Windsurf was renamed to Devin.
|
|
700
|
+
if env_platform == "windsurf":
|
|
701
|
+
env_platform = "devin"
|
|
691
702
|
if env_platform in (
|
|
692
703
|
"claude",
|
|
693
704
|
"opencode",
|
|
@@ -698,7 +709,7 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
698
709
|
"kiro",
|
|
699
710
|
"gemini",
|
|
700
711
|
"antigravity",
|
|
701
|
-
"
|
|
712
|
+
"devin",
|
|
702
713
|
"qoder",
|
|
703
714
|
"codebuddy",
|
|
704
715
|
"copilot",
|
|
@@ -749,13 +760,16 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
749
760
|
):
|
|
750
761
|
return "antigravity"
|
|
751
762
|
|
|
752
|
-
# Check for
|
|
763
|
+
# Check for Devin workflow directory only when no other platform config
|
|
764
|
+
# exists. `.windsurf/workflows` is the legacy pre-rename path (still detected
|
|
765
|
+
# as devin for back-compat until users migrate via `trellis update --migrate`).
|
|
753
766
|
if (
|
|
754
|
-
project_root / ".
|
|
755
|
-
|
|
756
|
-
|
|
767
|
+
(project_root / ".devin" / "workflows").is_dir()
|
|
768
|
+
or (project_root / ".windsurf" / "workflows").is_dir()
|
|
769
|
+
) and not _has_other_platform_dir(
|
|
770
|
+
project_root, {".devin", ".windsurf"}
|
|
757
771
|
):
|
|
758
|
-
return "
|
|
772
|
+
return "devin"
|
|
759
773
|
|
|
760
774
|
# Check for .codebuddy directory (CodeBuddy-specific)
|
|
761
775
|
if (project_root / ".codebuddy").is_dir():
|
|
@@ -58,7 +58,10 @@ TRELLIS_IGNORED_SUBPATHS = (
|
|
|
58
58
|
)
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
def safe_trellis_paths_to_add(
|
|
61
|
+
def safe_trellis_paths_to_add(
|
|
62
|
+
repo_root: Path,
|
|
63
|
+
task_name: str | None = None,
|
|
64
|
+
) -> list[str]:
|
|
62
65
|
"""Return the list of repo-relative paths the auto-commit should stage.
|
|
63
66
|
|
|
64
67
|
Only includes paths that exist on disk so callers don't pass non-existent
|
|
@@ -68,12 +71,23 @@ def safe_trellis_paths_to_add(repo_root: Path) -> list[str]:
|
|
|
68
71
|
Included:
|
|
69
72
|
- .trellis/workspace/<developer>/journal-*.md
|
|
70
73
|
- .trellis/workspace/<developer>/index.md
|
|
71
|
-
- .trellis/tasks/<
|
|
72
|
-
|
|
74
|
+
- .trellis/tasks/<task_name>/ (ONLY the current task dir when
|
|
75
|
+
``task_name`` is passed; plus its archive location if the task
|
|
76
|
+
already lives under archive/)
|
|
73
77
|
|
|
74
78
|
Excluded (intentionally — these must not be staged):
|
|
75
79
|
- .trellis/.backup-*, .trellis/worktrees/,
|
|
76
80
|
.trellis/.template-hashes.json, .trellis/.runtime/, .trellis/.cache/
|
|
81
|
+
|
|
82
|
+
Scope contract (see #303 / break-loop analysis): when ``task_name`` is
|
|
83
|
+
passed, the task segment stages ONLY that task directory — it never walks
|
|
84
|
+
``tasks_dir.iterdir()`` over all active tasks. This mirrors
|
|
85
|
+
:func:`safe_archive_paths_to_add` and prevents dirty changes in OTHER
|
|
86
|
+
parallel-window task dirs from being bundled into the session auto-commit.
|
|
87
|
+
|
|
88
|
+
Backwards-compat: with no ``task_name``, the function walks every active
|
|
89
|
+
task directory (+ the archive subtree) the old wide way. New callers
|
|
90
|
+
should always pass ``task_name``.
|
|
77
91
|
"""
|
|
78
92
|
paths: list[str] = []
|
|
79
93
|
|
|
@@ -93,20 +107,36 @@ def safe_trellis_paths_to_add(repo_root: Path) -> list[str]:
|
|
|
93
107
|
f"{DIR_WORKFLOW}/{DIR_WORKSPACE}/{developer}/index.md"
|
|
94
108
|
)
|
|
95
109
|
|
|
96
|
-
# Active tasks: each direct child of tasks/ that is a directory and not
|
|
97
|
-
# the archive root. The archive subtree is added as a single path below.
|
|
98
110
|
tasks_dir = repo_root / DIR_WORKFLOW / DIR_TASKS
|
|
99
|
-
if tasks_dir.is_dir():
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
if not tasks_dir.is_dir():
|
|
112
|
+
return paths
|
|
113
|
+
|
|
114
|
+
if task_name is not None:
|
|
115
|
+
# Narrow scope — ONLY the current task directory (active or archived).
|
|
116
|
+
# Never iterdir() all tasks: parallel-window dirty task dirs must not
|
|
117
|
+
# leak into the session auto-commit.
|
|
118
|
+
active_task = tasks_dir / task_name
|
|
119
|
+
if active_task.is_dir():
|
|
120
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{task_name}")
|
|
121
|
+
archived_task = tasks_dir / DIR_ARCHIVE / task_name
|
|
122
|
+
if archived_task.is_dir():
|
|
123
|
+
paths.append(
|
|
124
|
+
f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}/{task_name}"
|
|
125
|
+
)
|
|
126
|
+
return paths
|
|
127
|
+
|
|
128
|
+
# Legacy wide scope (no task_name): each direct child of tasks/ that is a
|
|
129
|
+
# directory and not the archive root, plus the whole archive subtree.
|
|
130
|
+
for child in sorted(tasks_dir.iterdir()):
|
|
131
|
+
if not child.is_dir():
|
|
132
|
+
continue
|
|
133
|
+
if child.name == DIR_ARCHIVE:
|
|
134
|
+
continue
|
|
135
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{child.name}")
|
|
136
|
+
|
|
137
|
+
archive_dir = tasks_dir / DIR_ARCHIVE
|
|
138
|
+
if archive_dir.is_dir():
|
|
139
|
+
paths.append(f"{DIR_WORKFLOW}/{DIR_TASKS}/{DIR_ARCHIVE}")
|
|
110
140
|
|
|
111
141
|
return paths
|
|
112
142
|
|