@mindfoldhq/trellis 0.6.4 → 0.6.6
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 +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/channel/messages.js +1 -1
- package/dist/commands/channel/supervisor/stdout.d.ts +7 -5
- package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -1
- package/dist/commands/channel/supervisor/stdout.js +65 -18
- package/dist/commands/channel/supervisor/stdout.js.map +1 -1
- package/dist/commands/channel/supervisor.d.ts +13 -0
- package/dist/commands/channel/supervisor.d.ts.map +1 -1
- package/dist/commands/channel/supervisor.js +54 -2
- package/dist/commands/channel/supervisor.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.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +8 -1
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +83 -42
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/copilot.d.ts +1 -0
- package/dist/configurators/copilot.d.ts.map +1 -1
- package/dist/configurators/copilot.js +4 -1
- package/dist/configurators/copilot.js.map +1 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +27 -1
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/omp.d.ts +11 -0
- package/dist/configurators/omp.d.ts.map +1 -0
- package/dist/configurators/omp.js +51 -0
- package/dist/configurators/omp.js.map +1 -0
- package/dist/configurators/pi.d.ts.map +1 -1
- package/dist/configurators/pi.js +14 -4
- package/dist/configurators/pi.js.map +1 -1
- package/dist/configurators/shared.d.ts +7 -0
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +27 -0
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/trae.d.ts +17 -0
- package/dist/configurators/trae.d.ts.map +1 -0
- package/dist/configurators/trae.js +42 -0
- package/dist/configurators/trae.js.map +1 -0
- package/dist/configurators/zcode.d.ts +3 -3
- package/dist/configurators/zcode.js +12 -12
- package/dist/configurators/zcode.js.map +1 -1
- package/dist/migrations/manifests/0.6.5.json +9 -0
- package/dist/migrations/manifests/0.6.6.json +17 -0
- package/dist/templates/codex/hooks/session-start.py +6 -6
- package/dist/templates/codex/skills/brainstorm/SKILL.md +19 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/bundled-skills.md +2 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +3 -3
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +1 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +5 -5
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +21 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +1 -1
- package/dist/templates/common/skills/brainstorm.md +19 -1
- package/dist/templates/copilot/copilot-instructions.md +11 -0
- package/dist/templates/copilot/hooks/session-start.py +6 -6
- package/dist/templates/copilot/index.d.ts +6 -1
- package/dist/templates/copilot/index.d.ts.map +1 -1
- package/dist/templates/copilot/index.js +8 -1
- package/dist/templates/copilot/index.js.map +1 -1
- package/dist/templates/copilot/prompts/brainstorm.prompt.md +19 -1
- package/dist/templates/omp/agents/trellis-check.md +41 -0
- package/dist/templates/omp/agents/trellis-implement.md +45 -0
- package/dist/templates/omp/agents/trellis-research.md +30 -0
- package/dist/templates/omp/extensions/trellis/index.ts.txt +462 -0
- package/dist/templates/omp/index.d.ts +4 -0
- package/dist/templates/omp/index.d.ts.map +1 -0
- package/dist/templates/omp/index.js +9 -0
- package/dist/templates/omp/index.js.map +1 -0
- package/dist/templates/pi/agents/trellis-check.md +1 -1
- package/dist/templates/pi/agents/trellis-implement.md +1 -1
- package/dist/templates/pi/agents/trellis-research.md +1 -1
- package/dist/templates/pi/extensions/trellis/index.ts.txt +111 -9
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +1 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-workflow-state.py +41 -6
- package/dist/templates/shared-hooks/session-start.py +12 -7
- package/dist/templates/trae/agents/trellis-check.md +108 -0
- package/dist/templates/trae/agents/trellis-implement.md +103 -0
- package/dist/templates/trae/agents/trellis-research.md +137 -0
- package/dist/templates/trae/hooks.json +27 -0
- package/dist/templates/trae/index.d.ts +15 -0
- package/dist/templates/trae/index.d.ts.map +1 -0
- package/dist/templates/trae/index.js +15 -0
- package/dist/templates/trae/index.js.map +1 -0
- package/dist/templates/trellis/scripts/add_session.py +65 -17
- package/dist/templates/trellis/scripts/common/active_task.py +2 -0
- package/dist/templates/trellis/scripts/common/cli_adapter.py +72 -11
- package/dist/templates/trellis/scripts/common/config.py +29 -0
- package/dist/templates/trellis/scripts/common/session_context.py +1 -1
- package/dist/templates/trellis/scripts/common/task_store.py +79 -19
- package/dist/templates/trellis/scripts/task.py +8 -2
- package/dist/templates/trellis/workflow.md +22 -20
- package/dist/templates/zcode/agents/trellis-research.md +133 -0
- package/dist/templates/zcode/index.d.ts +6 -5
- package/dist/templates/zcode/index.d.ts.map +1 -1
- package/dist/templates/zcode/index.js +6 -5
- package/dist/templates/zcode/index.js.map +1 -1
- 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 +45 -2
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/uninstall-scrubbers.d.ts +1 -0
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
- package/dist/utils/uninstall-scrubbers.js +19 -0
- package/dist/utils/uninstall-scrubbers.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: trellis-research
|
|
3
|
+
description: |
|
|
4
|
+
Code and tech search expert. Finds files, patterns, and tech solutions, and PERSISTS every finding to the current task's research/ directory. No code modifications outside that directory.
|
|
5
|
+
tools: Read, Write, Glob, Grep, Bash, Skill, mcp__*
|
|
6
|
+
---
|
|
7
|
+
# Research Agent
|
|
8
|
+
|
|
9
|
+
You are the Research Agent in the Trellis workflow.
|
|
10
|
+
|
|
11
|
+
## Core Principle
|
|
12
|
+
|
|
13
|
+
**You do one thing: find, explain, and PERSIST information.**
|
|
14
|
+
|
|
15
|
+
Conversations get compacted; files don't. Every research output MUST end up as a file under `{TASK_DIR}/research/`. Returning findings only through the chat reply is a failure — the caller cannot read them next session.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Core Responsibilities
|
|
20
|
+
|
|
21
|
+
1. **Internal Search** — locate files/components, understand code logic, discover patterns (Glob, Grep, Read)
|
|
22
|
+
2. **External Search** — library docs, API references, best practices (web search)
|
|
23
|
+
3. **Persist** — write each research topic to `{TASK_DIR}/research/<topic>.md`
|
|
24
|
+
4. **Report** — return file paths + one-line summaries to the main agent (not full content)
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Workflow
|
|
29
|
+
|
|
30
|
+
### Step 1: Resolve Current Task
|
|
31
|
+
|
|
32
|
+
Run `python3 ./.trellis/scripts/task.py current --source` → active task path. If no active task is set, ask the user where to write output; do NOT guess.
|
|
33
|
+
|
|
34
|
+
Ensure `{TASK_DIR}/research/` exists:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
mkdir -p <TASK_DIR>/research
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Step 2: Understand Search Request
|
|
41
|
+
|
|
42
|
+
Classify: internal / external / mixed. Determine scope (global / specific directory) and expected shape (file list / pattern notes / tech comparison).
|
|
43
|
+
|
|
44
|
+
### Step 3: Execute Search
|
|
45
|
+
|
|
46
|
+
Run independent searches in parallel (Glob + Grep + web) for efficiency.
|
|
47
|
+
|
|
48
|
+
### Step 4: Persist Each Topic
|
|
49
|
+
|
|
50
|
+
For each distinct research topic, Write a markdown file at `{TASK_DIR}/research/<topic-slug>.md`. Use the File Format below.
|
|
51
|
+
|
|
52
|
+
### Step 5: Report to Main Agent
|
|
53
|
+
|
|
54
|
+
Reply with ONLY:
|
|
55
|
+
|
|
56
|
+
- List of files written (paths relative to repo root)
|
|
57
|
+
- One-line summary per file
|
|
58
|
+
- Any critical caveats that the main agent needs to know right now
|
|
59
|
+
|
|
60
|
+
Do NOT paste full research content into the reply. The files are the contract.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Scope Limits (Strict)
|
|
65
|
+
|
|
66
|
+
### Write ALLOWED
|
|
67
|
+
|
|
68
|
+
- `{TASK_DIR}/research/*.md` — your own output
|
|
69
|
+
- Creating `{TASK_DIR}/research/` if it doesn't exist (via `mkdir -p`)
|
|
70
|
+
|
|
71
|
+
### Write FORBIDDEN
|
|
72
|
+
|
|
73
|
+
- Code files (`src/`, `lib/`, …)
|
|
74
|
+
- Spec files (`.trellis/spec/`) — main agent should use `update-spec` skill instead
|
|
75
|
+
- `.trellis/scripts/`, `.trellis/workflow.md`, platform config (`.claude/`, `.cursor/`, `.trae/`, etc.)
|
|
76
|
+
- Other task directories
|
|
77
|
+
- Any git operation (commit / push / branch / merge)
|
|
78
|
+
|
|
79
|
+
If the user asks you to edit code, decline and suggest spawning `implement` instead.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## File Format
|
|
84
|
+
|
|
85
|
+
Each `{TASK_DIR}/research/<topic>.md` should follow:
|
|
86
|
+
|
|
87
|
+
```markdown
|
|
88
|
+
# Research: <topic>
|
|
89
|
+
|
|
90
|
+
- **Query**: <original query>
|
|
91
|
+
- **Scope**: <internal / external / mixed>
|
|
92
|
+
- **Date**: <YYYY-MM-DD>
|
|
93
|
+
|
|
94
|
+
## Findings
|
|
95
|
+
|
|
96
|
+
### Files Found
|
|
97
|
+
|
|
98
|
+
| File Path | Description |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `src/services/xxx.ts` | Main implementation |
|
|
101
|
+
| `src/types/xxx.ts` | Type definitions |
|
|
102
|
+
|
|
103
|
+
### Code Patterns
|
|
104
|
+
|
|
105
|
+
<describe patterns, cite file:line>
|
|
106
|
+
|
|
107
|
+
### External References
|
|
108
|
+
|
|
109
|
+
- [Library X docs](url) — <why relevant, version constraints>
|
|
110
|
+
|
|
111
|
+
### Related Specs
|
|
112
|
+
|
|
113
|
+
- `.trellis/spec/xxx.md` — <description>
|
|
114
|
+
|
|
115
|
+
## Caveats / Not Found
|
|
116
|
+
|
|
117
|
+
<anything incomplete or uncertain>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Guidelines
|
|
123
|
+
|
|
124
|
+
### DO
|
|
125
|
+
|
|
126
|
+
- Provide specific file paths and line numbers
|
|
127
|
+
- Quote actual code snippets
|
|
128
|
+
- Persist every topic to its own file
|
|
129
|
+
- Return file paths in your reply, not the full content
|
|
130
|
+
- Mark "not found" explicitly when searches come up empty
|
|
131
|
+
|
|
132
|
+
### DON'T
|
|
133
|
+
|
|
134
|
+
- Don't write code or modify files outside `{TASK_DIR}/research/`
|
|
135
|
+
- Don't guess uncertain info
|
|
136
|
+
- Don't paste full research text into the reply (files are the deliverable)
|
|
137
|
+
- Don't propose improvements or critique implementation (that's not your role)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "{{PYTHON_CMD}} .trae/hooks/session-start.py",
|
|
10
|
+
"timeout": 30
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"UserPromptSubmit": [
|
|
16
|
+
{
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "{{PYTHON_CMD}} .trae/hooks/inject-workflow-state.py",
|
|
21
|
+
"timeout": 15
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trae IDE templates
|
|
3
|
+
*
|
|
4
|
+
* These are GENERIC templates for user projects.
|
|
5
|
+
*
|
|
6
|
+
* Directory structure:
|
|
7
|
+
* trae/
|
|
8
|
+
* ├── agents/ # Multi-agent pipeline agents (Markdown)
|
|
9
|
+
* └── hooks.json # Hook configuration
|
|
10
|
+
*/
|
|
11
|
+
import { type AgentTemplate, type HookTemplate } from "../template-utils.js";
|
|
12
|
+
export type { AgentTemplate, HookTemplate };
|
|
13
|
+
export declare const getAllAgents: () => AgentTemplate[];
|
|
14
|
+
export declare const getSettingsTemplate: () => HookTemplate;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trae/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAE9B,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC;AAI5C,eAAO,MAAM,YAAY,QAAO,aAAa,EAAoB,CAAC;AAClE,eAAO,MAAM,mBAAmB,QAAO,YACZ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trae IDE templates
|
|
3
|
+
*
|
|
4
|
+
* These are GENERIC templates for user projects.
|
|
5
|
+
*
|
|
6
|
+
* Directory structure:
|
|
7
|
+
* trae/
|
|
8
|
+
* ├── agents/ # Multi-agent pipeline agents (Markdown)
|
|
9
|
+
* └── hooks.json # Hook configuration
|
|
10
|
+
*/
|
|
11
|
+
import { createTemplateReader, } from "../template-utils.js";
|
|
12
|
+
const { listMdAgents, getSettings } = createTemplateReader(import.meta.url);
|
|
13
|
+
export const getAllAgents = () => listMdAgents();
|
|
14
|
+
export const getSettingsTemplate = () => getSettings("hooks.json");
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trae/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,oBAAoB,GAGrB,MAAM,sBAAsB,CAAC;AAI9B,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,GAAG,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE5E,MAAM,CAAC,MAAM,YAAY,GAAG,GAAoB,EAAE,CAAC,YAAY,EAAE,CAAC;AAClE,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAiB,EAAE,CACpD,WAAW,CAAC,YAAY,CAAC,CAAC"}
|
|
@@ -14,7 +14,7 @@ Usage:
|
|
|
14
14
|
|
|
15
15
|
Branch resolution order:
|
|
16
16
|
1. --branch CLI arg (explicit)
|
|
17
|
-
2. task.json branch field (from active task)
|
|
17
|
+
2. task.json branch field (from active task, if still exists)
|
|
18
18
|
3. git branch --show-current (auto-detect)
|
|
19
19
|
4. None (omitted gracefully)
|
|
20
20
|
"""
|
|
@@ -44,6 +44,7 @@ from common.safe_commit import (
|
|
|
44
44
|
safe_trellis_paths_to_add,
|
|
45
45
|
)
|
|
46
46
|
from common.tasks import load_task
|
|
47
|
+
from common.types import TaskInfo
|
|
47
48
|
from common.config import (
|
|
48
49
|
get_packages,
|
|
49
50
|
get_session_auto_commit,
|
|
@@ -55,6 +56,12 @@ from common.config import (
|
|
|
55
56
|
)
|
|
56
57
|
|
|
57
58
|
|
|
59
|
+
DEFAULT_MAIN_CHANGES = (
|
|
60
|
+
"- Detailed change bullets were not supplied; see the summary above."
|
|
61
|
+
)
|
|
62
|
+
DEFAULT_TESTING = "- Validation was not recorded for this session."
|
|
63
|
+
|
|
64
|
+
|
|
58
65
|
# =============================================================================
|
|
59
66
|
# Helper Functions
|
|
60
67
|
# =============================================================================
|
|
@@ -126,6 +133,56 @@ def count_journal_files(dev_dir: Path, active_num: int) -> str:
|
|
|
126
133
|
return "\n".join(result_lines)
|
|
127
134
|
|
|
128
135
|
|
|
136
|
+
def get_current_git_branch(repo_root: Path) -> str | None:
|
|
137
|
+
"""Return the current checkout branch, or None for detached/non-git states."""
|
|
138
|
+
rc, branch_out, _ = run_git(["branch", "--show-current"], cwd=repo_root)
|
|
139
|
+
if rc != 0:
|
|
140
|
+
return None
|
|
141
|
+
detected = branch_out.strip()
|
|
142
|
+
return detected or None
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def branch_ref_exists(repo_root: Path, branch: str) -> bool:
|
|
146
|
+
"""Return True when branch exists locally or as the local origin ref."""
|
|
147
|
+
for ref in (f"refs/heads/{branch}", f"refs/remotes/origin/{branch}"):
|
|
148
|
+
rc, _, _ = run_git(["show-ref", "--verify", "--quiet", ref], cwd=repo_root)
|
|
149
|
+
if rc == 0:
|
|
150
|
+
return True
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def resolve_session_branch(
|
|
155
|
+
repo_root: Path,
|
|
156
|
+
cli_branch: str | None,
|
|
157
|
+
task_data: TaskInfo | None,
|
|
158
|
+
) -> str | None:
|
|
159
|
+
"""Resolve journal branch without trusting stale task.json branch fields."""
|
|
160
|
+
if cli_branch:
|
|
161
|
+
return cli_branch
|
|
162
|
+
|
|
163
|
+
current_branch = get_current_git_branch(repo_root)
|
|
164
|
+
raw_task_branch = task_data.raw.get("branch") if task_data else None
|
|
165
|
+
task_branch = raw_task_branch.strip() if isinstance(raw_task_branch, str) else ""
|
|
166
|
+
if not task_branch:
|
|
167
|
+
return current_branch
|
|
168
|
+
|
|
169
|
+
if branch_ref_exists(repo_root, task_branch):
|
|
170
|
+
return task_branch
|
|
171
|
+
|
|
172
|
+
if current_branch:
|
|
173
|
+
print(
|
|
174
|
+
f"Warning: task.json branch '{task_branch}' no longer exists locally or as origin/{task_branch}; using current branch '{current_branch}'.",
|
|
175
|
+
file=sys.stderr,
|
|
176
|
+
)
|
|
177
|
+
return current_branch
|
|
178
|
+
|
|
179
|
+
print(
|
|
180
|
+
f"Warning: task.json branch '{task_branch}' no longer exists locally or as origin/{task_branch}; omitting branch.",
|
|
181
|
+
file=sys.stderr,
|
|
182
|
+
)
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
|
|
129
186
|
def create_new_journal_file(
|
|
130
187
|
dev_dir: Path, num: int, developer: str, today: str, max_lines: int = 2000,
|
|
131
188
|
) -> Path:
|
|
@@ -154,6 +211,7 @@ def generate_session_content(
|
|
|
154
211
|
today: str,
|
|
155
212
|
package: str | None = None,
|
|
156
213
|
branch: str | None = None,
|
|
214
|
+
testing_content: str = DEFAULT_TESTING,
|
|
157
215
|
) -> str:
|
|
158
216
|
"""Generate session content."""
|
|
159
217
|
if commit and commit != "-":
|
|
@@ -189,7 +247,7 @@ def generate_session_content(
|
|
|
189
247
|
|
|
190
248
|
### Testing
|
|
191
249
|
|
|
192
|
-
|
|
250
|
+
{testing_content}
|
|
193
251
|
|
|
194
252
|
### Status
|
|
195
253
|
|
|
@@ -395,8 +453,8 @@ def _auto_commit_workspace(repo_root: Path) -> None:
|
|
|
395
453
|
def add_session(
|
|
396
454
|
title: str,
|
|
397
455
|
commit: str = "-",
|
|
398
|
-
summary: str = "
|
|
399
|
-
extra_content: str =
|
|
456
|
+
summary: str = "Session summary was not supplied.",
|
|
457
|
+
extra_content: str = DEFAULT_MAIN_CHANGES,
|
|
400
458
|
auto_commit: bool = True,
|
|
401
459
|
package: str | None = None,
|
|
402
460
|
branch: str | None = None,
|
|
@@ -503,7 +561,7 @@ def main() -> int:
|
|
|
503
561
|
)
|
|
504
562
|
parser.add_argument("--title", required=True, help="Session title")
|
|
505
563
|
parser.add_argument("--commit", default="-", help="Comma-separated commit hashes")
|
|
506
|
-
parser.add_argument("--summary", default="
|
|
564
|
+
parser.add_argument("--summary", default="Session summary was not supplied.", help="Brief summary")
|
|
507
565
|
parser.add_argument("--content-file", help="Path to file with detailed content")
|
|
508
566
|
parser.add_argument("--package", help="Package name tag (e.g., cli, docs-site)")
|
|
509
567
|
parser.add_argument("--branch", help="Branch name (auto-detected if omitted)")
|
|
@@ -514,7 +572,7 @@ def main() -> int:
|
|
|
514
572
|
|
|
515
573
|
args = parser.parse_args()
|
|
516
574
|
|
|
517
|
-
extra_content =
|
|
575
|
+
extra_content = DEFAULT_MAIN_CHANGES
|
|
518
576
|
if args.content_file:
|
|
519
577
|
content_path = Path(args.content_file)
|
|
520
578
|
if content_path.is_file():
|
|
@@ -543,17 +601,7 @@ def main() -> int:
|
|
|
543
601
|
task_package = task_data.package if task_data else None
|
|
544
602
|
package = resolve_package(task_package, repo_root)
|
|
545
603
|
|
|
546
|
-
|
|
547
|
-
branch = args.branch
|
|
548
|
-
|
|
549
|
-
if not branch:
|
|
550
|
-
if task_data and task_data.raw.get("branch"):
|
|
551
|
-
branch = task_data.raw["branch"]
|
|
552
|
-
else:
|
|
553
|
-
_, branch_out, _ = run_git(["branch", "--show-current"], cwd=repo_root)
|
|
554
|
-
detected = branch_out.strip()
|
|
555
|
-
if detected:
|
|
556
|
-
branch = detected
|
|
604
|
+
branch = resolve_session_branch(repo_root, args.branch, task_data)
|
|
557
605
|
|
|
558
606
|
return add_session(
|
|
559
607
|
args.title, args.commit, args.summary, extra_content,
|
|
@@ -43,6 +43,7 @@ _KNOWN_PLATFORMS = {
|
|
|
43
43
|
"kiro",
|
|
44
44
|
"copilot",
|
|
45
45
|
"pi",
|
|
46
|
+
"trae",
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
_ENV_SESSION_KEYS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
@@ -57,6 +58,7 @@ _ENV_SESSION_KEYS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
|
57
58
|
("kiro", ("KIRO_SESSION_ID",)),
|
|
58
59
|
("copilot", ("COPILOT_SESSION_ID", "COPILOT_SESSIONID")),
|
|
59
60
|
("pi", ("PI_SESSION_ID", "PI_SESSIONID")),
|
|
61
|
+
("trae", ("TRAE_SESSION_ID",)),
|
|
60
62
|
)
|
|
61
63
|
_ENV_CONVERSATION_KEYS: tuple[tuple[str, tuple[str, ...]], ...] = (
|
|
62
64
|
("cursor", ("CURSOR_CONVERSATION_ID", "CURSOR_CONVERSATIONID")),
|
|
@@ -19,6 +19,7 @@ Supported platforms:
|
|
|
19
19
|
- copilot: GitHub Copilot (VS Code)
|
|
20
20
|
- droid: Factory Droid (commands-based)
|
|
21
21
|
- pi: Pi Agent (extension-backed)
|
|
22
|
+
- trae: Trae IDE (IDE-only, hooks-based)
|
|
22
23
|
|
|
23
24
|
Usage:
|
|
24
25
|
from common.cli_adapter import CLIAdapter
|
|
@@ -53,6 +54,8 @@ Platform = Literal[
|
|
|
53
54
|
"copilot",
|
|
54
55
|
"droid",
|
|
55
56
|
"pi",
|
|
57
|
+
"trae",
|
|
58
|
+
"omp",
|
|
56
59
|
]
|
|
57
60
|
|
|
58
61
|
|
|
@@ -97,7 +100,7 @@ class CLIAdapter:
|
|
|
97
100
|
"""Get platform-specific config directory name.
|
|
98
101
|
|
|
99
102
|
Returns:
|
|
100
|
-
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.devin', '.qoder', '.codebuddy', '.github/copilot', '.factory', or '.
|
|
103
|
+
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.codex', '.kilocode', '.kiro', '.gemini', '.agent', '.devin', '.qoder', '.codebuddy', '.github/copilot', '.factory', '.pi', or '.trae')
|
|
101
104
|
"""
|
|
102
105
|
if self.platform == "opencode":
|
|
103
106
|
return ".opencode"
|
|
@@ -127,6 +130,10 @@ class CLIAdapter:
|
|
|
127
130
|
return ".factory"
|
|
128
131
|
elif self.platform == "pi":
|
|
129
132
|
return ".pi"
|
|
133
|
+
elif self.platform == "trae":
|
|
134
|
+
return ".trae"
|
|
135
|
+
elif self.platform == "omp":
|
|
136
|
+
return ".omp"
|
|
130
137
|
else:
|
|
131
138
|
return ".claude"
|
|
132
139
|
|
|
@@ -137,7 +144,7 @@ class CLIAdapter:
|
|
|
137
144
|
project_root: Project root directory
|
|
138
145
|
|
|
139
146
|
Returns:
|
|
140
|
-
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .devin, .qoder, .codebuddy, .github/copilot, .factory, or .
|
|
147
|
+
Path to config directory (.claude, .opencode, .cursor, .iflow, .codex, .kilocode, .kiro, .gemini, .agent, .devin, .qoder, .codebuddy, .github/copilot, .factory, .pi, or .trae)
|
|
141
148
|
"""
|
|
142
149
|
return project_root / self.config_dir_name
|
|
143
150
|
|
|
@@ -184,6 +191,17 @@ class CLIAdapter:
|
|
|
184
191
|
filename = filename[:-3]
|
|
185
192
|
return prompts_dir / f"trellis-{filename}.md"
|
|
186
193
|
return prompts_dir / Path(*parts)
|
|
194
|
+
if self.platform == "omp":
|
|
195
|
+
commands_dir = self.get_config_dir(project_root) / "commands"
|
|
196
|
+
if not parts:
|
|
197
|
+
return commands_dir
|
|
198
|
+
if len(parts) >= 2 and parts[0] == "trellis":
|
|
199
|
+
filename = parts[-1]
|
|
200
|
+
if filename.endswith(".md"):
|
|
201
|
+
filename = filename[:-3]
|
|
202
|
+
return commands_dir / f"trellis-{filename}.md"
|
|
203
|
+
return commands_dir / Path(*parts)
|
|
204
|
+
|
|
187
205
|
|
|
188
206
|
if self.platform == "devin":
|
|
189
207
|
workflow_dir = self.get_config_dir(project_root) / "workflows"
|
|
@@ -268,6 +286,8 @@ class CLIAdapter:
|
|
|
268
286
|
return f".factory/commands/trellis/{name}.md"
|
|
269
287
|
elif self.platform == "pi":
|
|
270
288
|
return f".pi/prompts/trellis-{name}.md"
|
|
289
|
+
elif self.platform == "omp":
|
|
290
|
+
return f".omp/commands/trellis-{name}.md"
|
|
271
291
|
else:
|
|
272
292
|
return f"{self.config_dir_name}/commands/trellis/{name}.md"
|
|
273
293
|
|
|
@@ -305,6 +325,10 @@ class CLIAdapter:
|
|
|
305
325
|
return {}
|
|
306
326
|
elif self.platform == "pi":
|
|
307
327
|
return {}
|
|
328
|
+
elif self.platform == "trae":
|
|
329
|
+
return {}
|
|
330
|
+
elif self.platform == "omp":
|
|
331
|
+
return {}
|
|
308
332
|
else:
|
|
309
333
|
return {"CLAUDE_NON_INTERACTIVE": "1"}
|
|
310
334
|
|
|
@@ -390,6 +414,14 @@ class CLIAdapter:
|
|
|
390
414
|
)
|
|
391
415
|
elif self.platform == "pi":
|
|
392
416
|
cmd = ["pi", "-p", prompt]
|
|
417
|
+
elif self.platform == "trae":
|
|
418
|
+
raise ValueError(
|
|
419
|
+
"Trae is IDE-only; CLI agent run is not supported."
|
|
420
|
+
)
|
|
421
|
+
elif self.platform == "omp":
|
|
422
|
+
raise ValueError(
|
|
423
|
+
"OMP uses native task tool for agent runs; CLI agent run is not supported."
|
|
424
|
+
)
|
|
393
425
|
|
|
394
426
|
else: # claude
|
|
395
427
|
cmd = ["claude", "-p"]
|
|
@@ -456,6 +488,14 @@ class CLIAdapter:
|
|
|
456
488
|
)
|
|
457
489
|
elif self.platform == "pi":
|
|
458
490
|
return ["pi", "-c", session_id]
|
|
491
|
+
elif self.platform == "trae":
|
|
492
|
+
raise ValueError(
|
|
493
|
+
"Trae is IDE-only; CLI resume is not supported."
|
|
494
|
+
)
|
|
495
|
+
elif self.platform == "omp":
|
|
496
|
+
raise ValueError(
|
|
497
|
+
"OMP uses native task tool for agent runs; CLI resume is not supported."
|
|
498
|
+
)
|
|
459
499
|
else:
|
|
460
500
|
return ["claude", "--resume", session_id]
|
|
461
501
|
|
|
@@ -530,6 +570,10 @@ class CLIAdapter:
|
|
|
530
570
|
return "droid"
|
|
531
571
|
elif self.platform == "pi":
|
|
532
572
|
return "pi"
|
|
573
|
+
elif self.platform == "trae":
|
|
574
|
+
return "trae"
|
|
575
|
+
elif self.platform == "omp":
|
|
576
|
+
return "omp"
|
|
533
577
|
else:
|
|
534
578
|
return "claude"
|
|
535
579
|
|
|
@@ -594,7 +638,7 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
594
638
|
"""Get CLI adapter for the specified platform.
|
|
595
639
|
|
|
596
640
|
Args:
|
|
597
|
-
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', or '
|
|
641
|
+
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', or 'trae')
|
|
598
642
|
|
|
599
643
|
Returns:
|
|
600
644
|
CLIAdapter instance
|
|
@@ -625,9 +669,11 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
625
669
|
"copilot",
|
|
626
670
|
"droid",
|
|
627
671
|
"pi",
|
|
672
|
+
"trae",
|
|
673
|
+
"omp",
|
|
628
674
|
):
|
|
629
675
|
raise ValueError(
|
|
630
|
-
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', or '
|
|
676
|
+
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', 'trae', or 'omp')"
|
|
631
677
|
)
|
|
632
678
|
|
|
633
679
|
return CLIAdapter(platform=platform) # type: ignore
|
|
@@ -650,6 +696,8 @@ _ALL_PLATFORM_CONFIG_DIRS = (
|
|
|
650
696
|
".github/copilot",
|
|
651
697
|
".factory",
|
|
652
698
|
".pi",
|
|
699
|
+
".trae",
|
|
700
|
+
".omp",
|
|
653
701
|
)
|
|
654
702
|
"""Platform-specific config directory names used by detect_platform exclusion
|
|
655
703
|
checks. `.agents/skills/` is NOT listed here: it is a shared cross-platform
|
|
@@ -675,22 +723,25 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
675
723
|
2. .opencode directory exists → opencode
|
|
676
724
|
3. .iflow directory exists → iflow
|
|
677
725
|
4. .cursor directory exists (without .claude) → cursor
|
|
678
|
-
5. .
|
|
679
|
-
6. .
|
|
680
|
-
7. .
|
|
681
|
-
8. .
|
|
726
|
+
5. .gemini directory exists → gemini
|
|
727
|
+
6. .codex exists and no other platform dirs → codex
|
|
728
|
+
7. .kilocode directory exists → kilo
|
|
729
|
+
8. .kiro/skills exists and no other platform dirs → kiro
|
|
682
730
|
9. .agent/workflows exists and no other platform dirs → antigravity
|
|
683
731
|
10. .devin/workflows (or legacy .windsurf/workflows) exists and no other platform dirs → devin
|
|
684
732
|
11. .codebuddy directory exists → codebuddy
|
|
685
733
|
12. .qoder directory exists → qoder
|
|
686
|
-
13. .
|
|
687
|
-
14.
|
|
734
|
+
13. .github/copilot directory exists → copilot
|
|
735
|
+
14. .factory directory exists → droid
|
|
736
|
+
15. .pi directory exists → pi
|
|
737
|
+
16. .trae directory exists → trae
|
|
738
|
+
17. Default → claude
|
|
688
739
|
|
|
689
740
|
Args:
|
|
690
741
|
project_root: Project root directory
|
|
691
742
|
|
|
692
743
|
Returns:
|
|
693
|
-
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', or default 'claude')
|
|
744
|
+
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', 'devin', 'qoder', 'codebuddy', 'copilot', 'droid', 'pi', 'trae', or default 'claude')
|
|
694
745
|
"""
|
|
695
746
|
import os
|
|
696
747
|
|
|
@@ -715,6 +766,8 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
715
766
|
"copilot",
|
|
716
767
|
"droid",
|
|
717
768
|
"pi",
|
|
769
|
+
"trae",
|
|
770
|
+
"omp",
|
|
718
771
|
):
|
|
719
772
|
return env_platform # type: ignore
|
|
720
773
|
|
|
@@ -791,6 +844,14 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
791
844
|
if (project_root / ".pi").is_dir():
|
|
792
845
|
return "pi"
|
|
793
846
|
|
|
847
|
+
# Check for .trae directory (Trae IDE-specific)
|
|
848
|
+
if (project_root / ".trae").is_dir():
|
|
849
|
+
return "trae"
|
|
850
|
+
|
|
851
|
+
# Check for .omp directory (OMP-specific)
|
|
852
|
+
if (project_root / ".omp").is_dir():
|
|
853
|
+
return "omp"
|
|
854
|
+
|
|
794
855
|
# Fallback: checkout only has the Codex shared-skills layer
|
|
795
856
|
# (.agents/skills/trellis-* dirs) and no explicit platform config dir.
|
|
796
857
|
# Happens on fresh clones where .codex/ is gitignored/absent but the
|
|
@@ -167,6 +167,7 @@ def _next_content_line(lines: list[str], start: int) -> tuple[int, str]:
|
|
|
167
167
|
DEFAULT_SESSION_COMMIT_MESSAGE = "chore: record journal"
|
|
168
168
|
DEFAULT_MAX_JOURNAL_LINES = 2000
|
|
169
169
|
DEFAULT_SESSION_AUTO_COMMIT = True
|
|
170
|
+
DEFAULT_CODEX_DISPATCH_MODE = "inline"
|
|
170
171
|
|
|
171
172
|
CONFIG_FILE = "config.yaml"
|
|
172
173
|
|
|
@@ -243,6 +244,34 @@ def get_session_auto_commit(repo_root: Path | None = None) -> bool:
|
|
|
243
244
|
return DEFAULT_SESSION_AUTO_COMMIT
|
|
244
245
|
|
|
245
246
|
|
|
247
|
+
def get_codex_dispatch_mode(repo_root: Path | None = None) -> str:
|
|
248
|
+
"""Return Codex dispatch mode.
|
|
249
|
+
|
|
250
|
+
Default is ``inline``. ``sub-agent`` is an explicit opt-in because Codex
|
|
251
|
+
sub-agents do not inherit the parent session context.
|
|
252
|
+
"""
|
|
253
|
+
config = _load_config(repo_root)
|
|
254
|
+
codex = config.get("codex")
|
|
255
|
+
if codex is None:
|
|
256
|
+
return DEFAULT_CODEX_DISPATCH_MODE
|
|
257
|
+
if not isinstance(codex, dict):
|
|
258
|
+
print(
|
|
259
|
+
f"[WARN] invalid codex config: {codex!r}; using {DEFAULT_CODEX_DISPATCH_MODE}",
|
|
260
|
+
file=sys.stderr,
|
|
261
|
+
)
|
|
262
|
+
return DEFAULT_CODEX_DISPATCH_MODE
|
|
263
|
+
|
|
264
|
+
raw = codex.get("dispatch_mode", DEFAULT_CODEX_DISPATCH_MODE)
|
|
265
|
+
mode = str(raw).strip().lower()
|
|
266
|
+
if mode in ("inline", "sub-agent"):
|
|
267
|
+
return mode
|
|
268
|
+
print(
|
|
269
|
+
f"[WARN] invalid codex.dispatch_mode value: {raw!r}; using {DEFAULT_CODEX_DISPATCH_MODE}",
|
|
270
|
+
file=sys.stderr,
|
|
271
|
+
)
|
|
272
|
+
return DEFAULT_CODEX_DISPATCH_MODE
|
|
273
|
+
|
|
274
|
+
|
|
246
275
|
def get_hooks(event: str, repo_root: Path | None = None) -> list[str]:
|
|
247
276
|
"""Get hook commands for a lifecycle event.
|
|
248
277
|
|