@jahanxu/trellis 0.5.9 → 0.6.1
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 +74 -130
- package/dist/cli/index.js +1 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +30 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +11 -39
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +15 -3
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/kilo.d.ts +1 -1
- package/dist/configurators/kilo.d.ts.map +1 -1
- package/dist/configurators/kilo.js +2 -1
- package/dist/configurators/kilo.js.map +1 -1
- package/dist/configurators/qoder.d.ts +8 -0
- package/dist/configurators/qoder.d.ts.map +1 -0
- package/dist/configurators/qoder.js +52 -0
- package/dist/configurators/qoder.js.map +1 -0
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +3 -1
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/migrations/manifests/0.3.2.json +9 -0
- package/dist/migrations/manifests/0.3.3.json +9 -0
- package/dist/migrations/manifests/0.3.4.json +21 -0
- package/dist/migrations/manifests/0.3.5.json +9 -0
- package/dist/templates/claude/commands/trellis/record-session.md +12 -16
- package/dist/templates/codex/skills/record-session/SKILL.md +13 -17
- package/dist/templates/cursor/commands/trellis-record-session.md +12 -16
- package/dist/templates/extract.d.ts +7 -0
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +13 -0
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/gemini/commands/trellis/record-session.toml +12 -16
- package/dist/templates/iflow/commands/trellis/record-session.md +12 -16
- package/dist/templates/iflow/hooks/session-start.py +1 -0
- package/dist/templates/kilo/commands/trellis/record-session.md +12 -16
- package/dist/templates/kilo/index.d.ts +3 -3
- package/dist/templates/kilo/index.d.ts.map +1 -1
- package/dist/templates/kilo/index.js +7 -7
- package/dist/templates/kilo/index.js.map +1 -1
- package/dist/templates/kilo/workflows/before-backend-dev.md +13 -0
- package/dist/templates/kilo/workflows/before-frontend-dev.md +13 -0
- package/dist/templates/kilo/workflows/brainstorm.md +474 -0
- package/dist/templates/kilo/workflows/break-loop.md +125 -0
- package/dist/templates/kilo/workflows/check-backend.md +13 -0
- package/dist/templates/kilo/workflows/check-cross-layer.md +153 -0
- package/dist/templates/kilo/workflows/check-frontend.md +13 -0
- package/dist/templates/kilo/workflows/create-command.md +152 -0
- package/dist/templates/kilo/workflows/finish-work.md +129 -0
- package/dist/templates/kilo/workflows/integrate-skill.md +219 -0
- package/dist/templates/kilo/workflows/onboard.md +358 -0
- package/dist/templates/kilo/workflows/parallel.md +194 -0
- package/dist/templates/kilo/workflows/record-session.md +58 -0
- package/dist/templates/kilo/workflows/start.md +321 -0
- package/dist/templates/kilo/workflows/update-spec.md +285 -0
- package/dist/templates/kiro/skills/record-session/SKILL.md +13 -17
- package/dist/templates/opencode/commands/trellis/record-session.md +12 -16
- package/dist/templates/qoder/index.d.ts +18 -0
- package/dist/templates/qoder/index.d.ts.map +1 -0
- package/dist/templates/qoder/index.js +40 -0
- package/dist/templates/qoder/index.js.map +1 -0
- package/dist/templates/qoder/skills/before-backend-dev/SKILL.md +18 -0
- package/dist/templates/qoder/skills/before-frontend-dev/SKILL.md +18 -0
- package/dist/templates/qoder/skills/brainstorm/SKILL.md +479 -0
- package/dist/templates/qoder/skills/break-loop/SKILL.md +130 -0
- package/dist/templates/qoder/skills/check-backend/SKILL.md +18 -0
- package/dist/templates/qoder/skills/check-cross-layer/SKILL.md +158 -0
- package/dist/templates/qoder/skills/check-frontend/SKILL.md +18 -0
- package/dist/templates/qoder/skills/create-command/SKILL.md +101 -0
- package/dist/templates/qoder/skills/finish-work/SKILL.md +134 -0
- package/dist/templates/qoder/skills/integrate-skill/SKILL.md +221 -0
- package/dist/templates/qoder/skills/onboard/SKILL.md +363 -0
- package/dist/templates/qoder/skills/record-session/SKILL.md +63 -0
- package/dist/templates/qoder/skills/start/SKILL.md +326 -0
- package/dist/templates/qoder/skills/update-spec/SKILL.md +290 -0
- package/dist/templates/trellis/config.yaml +15 -0
- package/dist/templates/trellis/index.d.ts +3 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +4 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +52 -21
- package/dist/templates/trellis/scripts/common/__init__.py +3 -1
- package/dist/templates/trellis/scripts/common/cli_adapter.py +125 -20
- package/dist/templates/trellis/scripts/common/config.py +52 -0
- package/dist/templates/trellis/scripts/common/git_context.py +121 -11
- package/dist/templates/trellis/scripts/multi_agent/plan.py +4 -1
- package/dist/templates/trellis/scripts/multi_agent/start.py +5 -1
- package/dist/templates/trellis/scripts/task.py +26 -0
- package/dist/types/ai-tools.d.ts +3 -3
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +8 -0
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/proxy.d.ts +25 -0
- package/dist/utils/proxy.d.ts.map +1 -0
- package/dist/utils/proxy.js +60 -0
- package/dist/utils/proxy.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +11 -2
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +92 -19
- package/dist/utils/template-fetcher.js.map +1 -1
- package/dist/utils/template-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +1 -0
- package/dist/utils/template-hash.js.map +1 -1
- package/package.json +10 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,19 +10,9 @@ Usage:
|
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
-
import sys
|
|
14
|
-
|
|
15
|
-
# IMPORTANT: Force stdout to use UTF-8 on Windows
|
|
16
|
-
# This fixes UnicodeEncodeError when outputting non-ASCII characters
|
|
17
|
-
if sys.platform == "win32":
|
|
18
|
-
import io as _io
|
|
19
|
-
if hasattr(sys.stdout, "reconfigure"):
|
|
20
|
-
sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
21
|
-
elif hasattr(sys.stdout, "detach"):
|
|
22
|
-
sys.stdout = _io.TextIOWrapper(sys.stdout.detach(), encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
23
|
-
|
|
24
13
|
import argparse
|
|
25
14
|
import re
|
|
15
|
+
import subprocess
|
|
26
16
|
import sys
|
|
27
17
|
from datetime import datetime
|
|
28
18
|
from pathlib import Path
|
|
@@ -34,9 +24,7 @@ from common.paths import (
|
|
|
34
24
|
get_workspace_dir,
|
|
35
25
|
)
|
|
36
26
|
from common.developer import ensure_developer
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
MAX_LINES = 2000
|
|
27
|
+
from common.config import get_session_commit_message, get_max_journal_lines
|
|
40
28
|
|
|
41
29
|
|
|
42
30
|
# =============================================================================
|
|
@@ -110,14 +98,16 @@ def count_journal_files(dev_dir: Path, active_num: int) -> str:
|
|
|
110
98
|
return "\n".join(result_lines)
|
|
111
99
|
|
|
112
100
|
|
|
113
|
-
def create_new_journal_file(
|
|
101
|
+
def create_new_journal_file(
|
|
102
|
+
dev_dir: Path, num: int, developer: str, today: str, max_lines: int = 2000,
|
|
103
|
+
) -> Path:
|
|
114
104
|
"""Create a new journal file."""
|
|
115
105
|
prev_num = num - 1
|
|
116
106
|
new_file = dev_dir / f"{FILE_JOURNAL_PREFIX}{num}.md"
|
|
117
107
|
|
|
118
108
|
content = f"""# Journal - {developer} (Part {num})
|
|
119
109
|
|
|
120
|
-
> Continuation from `{FILE_JOURNAL_PREFIX}{prev_num}.md` (archived at ~{
|
|
110
|
+
> Continuation from `{FILE_JOURNAL_PREFIX}{prev_num}.md` (archived at ~{max_lines} lines)
|
|
121
111
|
> Started: {today}
|
|
122
112
|
|
|
123
113
|
---
|
|
@@ -281,11 +271,40 @@ def update_index(
|
|
|
281
271
|
# Main Function
|
|
282
272
|
# =============================================================================
|
|
283
273
|
|
|
274
|
+
def _auto_commit_workspace(repo_root: Path) -> None:
|
|
275
|
+
"""Stage .trellis/workspace and .trellis/tasks, then commit with a configured message."""
|
|
276
|
+
commit_msg = get_session_commit_message(repo_root)
|
|
277
|
+
subprocess.run(
|
|
278
|
+
["git", "add", "-A", ".trellis/workspace", ".trellis/tasks"],
|
|
279
|
+
cwd=repo_root,
|
|
280
|
+
capture_output=True,
|
|
281
|
+
)
|
|
282
|
+
# Check if there are staged changes
|
|
283
|
+
result = subprocess.run(
|
|
284
|
+
["git", "diff", "--cached", "--quiet", "--", ".trellis/workspace", ".trellis/tasks"],
|
|
285
|
+
cwd=repo_root,
|
|
286
|
+
)
|
|
287
|
+
if result.returncode == 0:
|
|
288
|
+
print("[OK] No workspace changes to commit.", file=sys.stderr)
|
|
289
|
+
return
|
|
290
|
+
commit_result = subprocess.run(
|
|
291
|
+
["git", "commit", "-m", commit_msg],
|
|
292
|
+
cwd=repo_root,
|
|
293
|
+
capture_output=True,
|
|
294
|
+
text=True,
|
|
295
|
+
)
|
|
296
|
+
if commit_result.returncode == 0:
|
|
297
|
+
print(f"[OK] Auto-committed: {commit_msg}", file=sys.stderr)
|
|
298
|
+
else:
|
|
299
|
+
print(f"[WARN] Auto-commit failed: {commit_result.stderr.strip()}", file=sys.stderr)
|
|
300
|
+
|
|
301
|
+
|
|
284
302
|
def add_session(
|
|
285
303
|
title: str,
|
|
286
304
|
commit: str = "-",
|
|
287
305
|
summary: str = "(Add summary)",
|
|
288
|
-
extra_content: str = "(Add details)"
|
|
306
|
+
extra_content: str = "(Add details)",
|
|
307
|
+
auto_commit: bool = True,
|
|
289
308
|
) -> int:
|
|
290
309
|
"""Add a new session."""
|
|
291
310
|
repo_root = get_repo_root()
|
|
@@ -301,6 +320,8 @@ def add_session(
|
|
|
301
320
|
print("Error: Workspace directory not found", file=sys.stderr)
|
|
302
321
|
return 1
|
|
303
322
|
|
|
323
|
+
max_lines = get_max_journal_lines(repo_root)
|
|
324
|
+
|
|
304
325
|
index_file = dev_dir / "index.md"
|
|
305
326
|
today = datetime.now().strftime("%Y-%m-%d")
|
|
306
327
|
|
|
@@ -330,10 +351,10 @@ def add_session(
|
|
|
330
351
|
target_file = journal_file
|
|
331
352
|
target_num = current_num
|
|
332
353
|
|
|
333
|
-
if current_lines + content_lines >
|
|
354
|
+
if current_lines + content_lines > max_lines:
|
|
334
355
|
target_num = current_num + 1
|
|
335
|
-
print(f"[!] Exceeds {
|
|
336
|
-
target_file = create_new_journal_file(dev_dir, target_num, developer, today)
|
|
356
|
+
print(f"[!] Exceeds {max_lines} lines, creating {FILE_JOURNAL_PREFIX}{target_num}.md", file=sys.stderr)
|
|
357
|
+
target_file = create_new_journal_file(dev_dir, target_num, developer, today, max_lines)
|
|
337
358
|
print(f"Created: {target_file}", file=sys.stderr)
|
|
338
359
|
|
|
339
360
|
# Append session content
|
|
@@ -358,6 +379,11 @@ def add_session(
|
|
|
358
379
|
print(f" - {target_file.name if target_file else 'journal'}", file=sys.stderr)
|
|
359
380
|
print(" - index.md", file=sys.stderr)
|
|
360
381
|
|
|
382
|
+
# Auto-commit workspace changes
|
|
383
|
+
if auto_commit:
|
|
384
|
+
print("", file=sys.stderr)
|
|
385
|
+
_auto_commit_workspace(repo_root)
|
|
386
|
+
|
|
361
387
|
return 0
|
|
362
388
|
|
|
363
389
|
|
|
@@ -374,6 +400,8 @@ def main() -> int:
|
|
|
374
400
|
parser.add_argument("--commit", default="-", help="Comma-separated commit hashes")
|
|
375
401
|
parser.add_argument("--summary", default="(Add summary)", help="Brief summary")
|
|
376
402
|
parser.add_argument("--content-file", help="Path to file with detailed content")
|
|
403
|
+
parser.add_argument("--no-commit", action="store_true",
|
|
404
|
+
help="Skip auto-commit of workspace changes")
|
|
377
405
|
|
|
378
406
|
args = parser.parse_args()
|
|
379
407
|
|
|
@@ -385,7 +413,10 @@ def main() -> int:
|
|
|
385
413
|
elif not sys.stdin.isatty():
|
|
386
414
|
extra_content = sys.stdin.read()
|
|
387
415
|
|
|
388
|
-
return add_session(
|
|
416
|
+
return add_session(
|
|
417
|
+
args.title, args.commit, args.summary, extra_content,
|
|
418
|
+
auto_commit=not args.no_commit,
|
|
419
|
+
)
|
|
389
420
|
|
|
390
421
|
|
|
391
422
|
if __name__ == "__main__":
|
|
@@ -36,11 +36,12 @@ def _configure_stream(stream: object) -> object:
|
|
|
36
36
|
if sys.platform == "win32":
|
|
37
37
|
sys.stdout = _configure_stream(sys.stdout) # type: ignore[assignment]
|
|
38
38
|
sys.stderr = _configure_stream(sys.stderr) # type: ignore[assignment]
|
|
39
|
+
sys.stdin = _configure_stream(sys.stdin) # type: ignore[assignment]
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
def configure_encoding() -> None:
|
|
42
43
|
"""
|
|
43
|
-
Configure stdout/stderr for UTF-8 encoding on Windows.
|
|
44
|
+
Configure stdout/stderr/stdin for UTF-8 encoding on Windows.
|
|
44
45
|
|
|
45
46
|
This is automatically called when importing from common,
|
|
46
47
|
but can be called manually for scripts that don't import common.
|
|
@@ -51,6 +52,7 @@ def configure_encoding() -> None:
|
|
|
51
52
|
if sys.platform == "win32":
|
|
52
53
|
sys.stdout = _configure_stream(sys.stdout) # type: ignore[assignment]
|
|
53
54
|
sys.stderr = _configure_stream(sys.stderr) # type: ignore[assignment]
|
|
55
|
+
sys.stdin = _configure_stream(sys.stdin) # type: ignore[assignment]
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
from .paths import (
|
|
@@ -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, and
|
|
4
|
+
Abstracts differences between Claude Code, OpenCode, Cursor, iFlow, Codex, Kilo, Kiro Code, Gemini CLI, Antigravity, and Qoder interfaces.
|
|
5
5
|
|
|
6
6
|
Supported platforms:
|
|
7
7
|
- claude: Claude Code (default)
|
|
@@ -13,6 +13,7 @@ Supported platforms:
|
|
|
13
13
|
- kiro: Kiro Code (skills-based)
|
|
14
14
|
- gemini: Gemini CLI
|
|
15
15
|
- antigravity: Antigravity (workflow-based)
|
|
16
|
+
- qoder: Qoder
|
|
16
17
|
|
|
17
18
|
Usage:
|
|
18
19
|
from common.cli_adapter import CLIAdapter
|
|
@@ -31,7 +32,18 @@ from dataclasses import dataclass
|
|
|
31
32
|
from pathlib import Path
|
|
32
33
|
from typing import ClassVar, Literal
|
|
33
34
|
|
|
34
|
-
Platform = Literal[
|
|
35
|
+
Platform = Literal[
|
|
36
|
+
"claude",
|
|
37
|
+
"opencode",
|
|
38
|
+
"cursor",
|
|
39
|
+
"iflow",
|
|
40
|
+
"codex",
|
|
41
|
+
"kilo",
|
|
42
|
+
"kiro",
|
|
43
|
+
"gemini",
|
|
44
|
+
"antigravity",
|
|
45
|
+
"qoder",
|
|
46
|
+
]
|
|
35
47
|
|
|
36
48
|
|
|
37
49
|
@dataclass
|
|
@@ -75,7 +87,7 @@ class CLIAdapter:
|
|
|
75
87
|
"""Get platform-specific config directory name.
|
|
76
88
|
|
|
77
89
|
Returns:
|
|
78
|
-
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.agents', '.kilocode', '.kiro', '.gemini', or '.
|
|
90
|
+
Directory name ('.claude', '.opencode', '.cursor', '.iflow', '.agents', '.kilocode', '.kiro', '.gemini', '.agent', or '.qoder')
|
|
79
91
|
"""
|
|
80
92
|
if self.platform == "opencode":
|
|
81
93
|
return ".opencode"
|
|
@@ -93,6 +105,8 @@ class CLIAdapter:
|
|
|
93
105
|
return ".gemini"
|
|
94
106
|
elif self.platform == "antigravity":
|
|
95
107
|
return ".agent"
|
|
108
|
+
elif self.platform == "qoder":
|
|
109
|
+
return ".qoder"
|
|
96
110
|
else:
|
|
97
111
|
return ".claude"
|
|
98
112
|
|
|
@@ -103,7 +117,7 @@ class CLIAdapter:
|
|
|
103
117
|
project_root: Project root directory
|
|
104
118
|
|
|
105
119
|
Returns:
|
|
106
|
-
Path to config directory (.claude, .opencode, .cursor, .iflow, .agents, .kilocode, .kiro, or .
|
|
120
|
+
Path to config directory (.claude, .opencode, .cursor, .iflow, .agents, .kilocode, .kiro, .gemini, .agent, or .qoder)
|
|
107
121
|
"""
|
|
108
122
|
return project_root / self.config_dir_name
|
|
109
123
|
|
|
@@ -135,7 +149,7 @@ class CLIAdapter:
|
|
|
135
149
|
Antigravity uses workflow directory: .agent/workflows/<name>.md
|
|
136
150
|
Claude/OpenCode use subdirectory: .claude/commands/trellis/<name>.md
|
|
137
151
|
"""
|
|
138
|
-
if self.platform
|
|
152
|
+
if self.platform in ("antigravity", "kilo"):
|
|
139
153
|
workflow_dir = self.get_config_dir(project_root) / "workflows"
|
|
140
154
|
if not parts:
|
|
141
155
|
return workflow_dir
|
|
@@ -151,7 +165,9 @@ class CLIAdapter:
|
|
|
151
165
|
if self.platform == "cursor" and len(parts) >= 2 and parts[0] == "trellis":
|
|
152
166
|
# Convert trellis/<name>.md to trellis-<name>.md
|
|
153
167
|
filename = parts[-1]
|
|
154
|
-
return
|
|
168
|
+
return (
|
|
169
|
+
self.get_config_dir(project_root) / "commands" / f"trellis-{filename}"
|
|
170
|
+
)
|
|
155
171
|
|
|
156
172
|
return self.get_config_dir(project_root) / "commands" / Path(*parts)
|
|
157
173
|
|
|
@@ -182,6 +198,8 @@ class CLIAdapter:
|
|
|
182
198
|
return f".gemini/commands/trellis/{name}.toml"
|
|
183
199
|
elif self.platform == "antigravity":
|
|
184
200
|
return f".agent/workflows/{name}.md"
|
|
201
|
+
elif self.platform == "kilo":
|
|
202
|
+
return f".kilocode/workflows/{name}.md"
|
|
185
203
|
else:
|
|
186
204
|
return f"{self.config_dir_name}/commands/trellis/{name}.md"
|
|
187
205
|
|
|
@@ -197,6 +215,8 @@ class CLIAdapter:
|
|
|
197
215
|
"""
|
|
198
216
|
if self.platform == "opencode":
|
|
199
217
|
return {"OPENCODE_NON_INTERACTIVE": "1"}
|
|
218
|
+
elif self.platform == "iflow":
|
|
219
|
+
return {"IFLOW_NON_INTERACTIVE": "1"}
|
|
200
220
|
elif self.platform == "codex":
|
|
201
221
|
return {"CODEX_NON_INTERACTIVE": "1"}
|
|
202
222
|
elif self.platform == "kiro":
|
|
@@ -205,6 +225,8 @@ class CLIAdapter:
|
|
|
205
225
|
return {} # Gemini CLI doesn't have a non-interactive env var
|
|
206
226
|
elif self.platform == "antigravity":
|
|
207
227
|
return {}
|
|
228
|
+
elif self.platform == "qoder":
|
|
229
|
+
return {}
|
|
208
230
|
else:
|
|
209
231
|
return {"CLAUDE_NON_INTERACTIVE": "1"}
|
|
210
232
|
|
|
@@ -255,6 +277,13 @@ class CLIAdapter:
|
|
|
255
277
|
|
|
256
278
|
cmd.append(prompt)
|
|
257
279
|
|
|
280
|
+
elif self.platform == "iflow":
|
|
281
|
+
cmd = ["iflow", "-p"]
|
|
282
|
+
cmd.extend(["-y", "--agent", mapped_agent])
|
|
283
|
+
# iFlow doesn't support --session-id on creation
|
|
284
|
+
if verbose:
|
|
285
|
+
cmd.append("--verbose")
|
|
286
|
+
cmd.append(prompt)
|
|
258
287
|
elif self.platform == "codex":
|
|
259
288
|
cmd = ["codex", "exec"]
|
|
260
289
|
cmd.append(prompt)
|
|
@@ -267,6 +296,8 @@ class CLIAdapter:
|
|
|
267
296
|
raise ValueError(
|
|
268
297
|
"Antigravity workflows are UI slash commands; CLI agent run is not supported."
|
|
269
298
|
)
|
|
299
|
+
elif self.platform == "qoder":
|
|
300
|
+
cmd = ["qodercli", "-p", prompt]
|
|
270
301
|
|
|
271
302
|
else: # claude
|
|
272
303
|
cmd = ["claude", "-p"]
|
|
@@ -292,13 +323,17 @@ class CLIAdapter:
|
|
|
292
323
|
"""Build CLI command for resuming a session.
|
|
293
324
|
|
|
294
325
|
Args:
|
|
295
|
-
session_id: Session ID to resume
|
|
326
|
+
session_id: Session ID to resume (ignored for iFlow)
|
|
296
327
|
|
|
297
328
|
Returns:
|
|
298
329
|
List of command arguments
|
|
299
330
|
"""
|
|
300
331
|
if self.platform == "opencode":
|
|
301
332
|
return ["opencode", "run", "--session", session_id]
|
|
333
|
+
elif self.platform == "iflow":
|
|
334
|
+
# iFlow uses -c to continue most recent conversation
|
|
335
|
+
# session_id is ignored as iFlow doesn't support session IDs
|
|
336
|
+
return ["iflow", "-c"]
|
|
302
337
|
elif self.platform == "codex":
|
|
303
338
|
return ["codex", "resume", session_id]
|
|
304
339
|
elif self.platform == "kiro":
|
|
@@ -309,6 +344,8 @@ class CLIAdapter:
|
|
|
309
344
|
raise ValueError(
|
|
310
345
|
"Antigravity workflows are UI slash commands; CLI resume is not supported."
|
|
311
346
|
)
|
|
347
|
+
elif self.platform == "qoder":
|
|
348
|
+
return ["qodercli", "--resume", session_id]
|
|
312
349
|
else:
|
|
313
350
|
return ["claude", "--resume", session_id]
|
|
314
351
|
|
|
@@ -348,6 +385,11 @@ class CLIAdapter:
|
|
|
348
385
|
"""Check if platform is Cursor."""
|
|
349
386
|
return self.platform == "cursor"
|
|
350
387
|
|
|
388
|
+
@property
|
|
389
|
+
def is_iflow(self) -> bool:
|
|
390
|
+
"""Check if platform is iFlow CLI."""
|
|
391
|
+
return self.platform == "iflow"
|
|
392
|
+
|
|
351
393
|
@property
|
|
352
394
|
def cli_name(self) -> str:
|
|
353
395
|
"""Get CLI executable name.
|
|
@@ -358,12 +400,16 @@ class CLIAdapter:
|
|
|
358
400
|
return "opencode"
|
|
359
401
|
elif self.is_cursor:
|
|
360
402
|
return "cursor" # Note: Cursor is IDE-only, no CLI
|
|
403
|
+
elif self.platform == "iflow":
|
|
404
|
+
return "iflow"
|
|
361
405
|
elif self.platform == "kiro":
|
|
362
406
|
return "kiro"
|
|
363
407
|
elif self.platform == "gemini":
|
|
364
408
|
return "gemini"
|
|
365
409
|
elif self.platform == "antigravity":
|
|
366
410
|
return "agy"
|
|
411
|
+
elif self.platform == "qoder":
|
|
412
|
+
return "qodercli"
|
|
367
413
|
else:
|
|
368
414
|
return "claude"
|
|
369
415
|
|
|
@@ -371,10 +417,10 @@ class CLIAdapter:
|
|
|
371
417
|
def supports_cli_agents(self) -> bool:
|
|
372
418
|
"""Check if platform supports running agents via CLI.
|
|
373
419
|
|
|
374
|
-
Claude Code and
|
|
420
|
+
Claude Code, OpenCode, and iFlow support CLI agent execution.
|
|
375
421
|
Cursor is IDE-only and doesn't support CLI agents.
|
|
376
422
|
"""
|
|
377
|
-
return self.platform in ("claude", "opencode")
|
|
423
|
+
return self.platform in ("claude", "opencode", "iflow")
|
|
378
424
|
|
|
379
425
|
# =========================================================================
|
|
380
426
|
# Session ID Handling
|
|
@@ -386,6 +432,7 @@ class CLIAdapter:
|
|
|
386
432
|
|
|
387
433
|
Claude Code: Yes (--session-id)
|
|
388
434
|
OpenCode: No (auto-generated, extract from logs)
|
|
435
|
+
iFlow: No (no session ID support)
|
|
389
436
|
"""
|
|
390
437
|
return self.platform == "claude"
|
|
391
438
|
|
|
@@ -418,7 +465,7 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
418
465
|
"""Get CLI adapter for the specified platform.
|
|
419
466
|
|
|
420
467
|
Args:
|
|
421
|
-
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro',
|
|
468
|
+
platform: Platform name ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', or 'qoder')
|
|
422
469
|
|
|
423
470
|
Returns:
|
|
424
471
|
CLIAdapter instance
|
|
@@ -426,8 +473,21 @@ def get_cli_adapter(platform: str = "claude") -> CLIAdapter:
|
|
|
426
473
|
Raises:
|
|
427
474
|
ValueError: If platform is not supported
|
|
428
475
|
"""
|
|
429
|
-
if platform not in (
|
|
430
|
-
|
|
476
|
+
if platform not in (
|
|
477
|
+
"claude",
|
|
478
|
+
"opencode",
|
|
479
|
+
"cursor",
|
|
480
|
+
"iflow",
|
|
481
|
+
"codex",
|
|
482
|
+
"kilo",
|
|
483
|
+
"kiro",
|
|
484
|
+
"gemini",
|
|
485
|
+
"antigravity",
|
|
486
|
+
"qoder",
|
|
487
|
+
):
|
|
488
|
+
raise ValueError(
|
|
489
|
+
f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', or 'qoder')"
|
|
490
|
+
)
|
|
431
491
|
|
|
432
492
|
return CLIAdapter(platform=platform) # type: ignore
|
|
433
493
|
|
|
@@ -445,19 +505,31 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
445
505
|
7. .kiro/skills exists and no other platform dirs → kiro
|
|
446
506
|
8. .gemini directory exists → gemini
|
|
447
507
|
9. .agent/workflows exists and no other platform dirs → antigravity
|
|
448
|
-
10.
|
|
508
|
+
10. .qoder directory exists → qoder
|
|
509
|
+
11. Default → claude
|
|
449
510
|
|
|
450
511
|
Args:
|
|
451
512
|
project_root: Project root directory
|
|
452
513
|
|
|
453
514
|
Returns:
|
|
454
|
-
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', or '
|
|
515
|
+
Detected platform ('claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', 'antigravity', or 'qoder')
|
|
455
516
|
"""
|
|
456
517
|
import os
|
|
457
518
|
|
|
458
519
|
# Check environment variable first
|
|
459
520
|
env_platform = os.environ.get("TRELLIS_PLATFORM", "").lower()
|
|
460
|
-
if env_platform in (
|
|
521
|
+
if env_platform in (
|
|
522
|
+
"claude",
|
|
523
|
+
"opencode",
|
|
524
|
+
"cursor",
|
|
525
|
+
"iflow",
|
|
526
|
+
"codex",
|
|
527
|
+
"kilo",
|
|
528
|
+
"kiro",
|
|
529
|
+
"gemini",
|
|
530
|
+
"antigravity",
|
|
531
|
+
"qoder",
|
|
532
|
+
):
|
|
461
533
|
return env_platform # type: ignore
|
|
462
534
|
|
|
463
535
|
# Check for .opencode directory (OpenCode-specific)
|
|
@@ -480,7 +552,16 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
480
552
|
return "gemini"
|
|
481
553
|
|
|
482
554
|
# Check for Codex skills directory only when no other platform config exists
|
|
483
|
-
other_platform_dirs_codex = (
|
|
555
|
+
other_platform_dirs_codex = (
|
|
556
|
+
".claude",
|
|
557
|
+
".cursor",
|
|
558
|
+
".iflow",
|
|
559
|
+
".opencode",
|
|
560
|
+
".kilocode",
|
|
561
|
+
".kiro",
|
|
562
|
+
".gemini",
|
|
563
|
+
".agent",
|
|
564
|
+
)
|
|
484
565
|
has_other_platform_config = any(
|
|
485
566
|
(project_root / directory).is_dir() for directory in other_platform_dirs_codex
|
|
486
567
|
)
|
|
@@ -492,7 +573,16 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
492
573
|
return "kilo"
|
|
493
574
|
|
|
494
575
|
# Check for Kiro skills directory only when no other platform config exists
|
|
495
|
-
other_platform_dirs_kiro = (
|
|
576
|
+
other_platform_dirs_kiro = (
|
|
577
|
+
".claude",
|
|
578
|
+
".cursor",
|
|
579
|
+
".iflow",
|
|
580
|
+
".opencode",
|
|
581
|
+
".agents",
|
|
582
|
+
".kilocode",
|
|
583
|
+
".gemini",
|
|
584
|
+
".agent",
|
|
585
|
+
)
|
|
496
586
|
has_other_platform_config = any(
|
|
497
587
|
(project_root / directory).is_dir() for directory in other_platform_dirs_kiro
|
|
498
588
|
)
|
|
@@ -500,13 +590,28 @@ def detect_platform(project_root: Path) -> Platform:
|
|
|
500
590
|
return "kiro"
|
|
501
591
|
|
|
502
592
|
# Check for Antigravity workflow directory only when no other platform config exists
|
|
503
|
-
other_platform_dirs_antigravity = (
|
|
593
|
+
other_platform_dirs_antigravity = (
|
|
594
|
+
".claude",
|
|
595
|
+
".cursor",
|
|
596
|
+
".iflow",
|
|
597
|
+
".opencode",
|
|
598
|
+
".agents",
|
|
599
|
+
".kilocode",
|
|
600
|
+
".kiro",
|
|
601
|
+
)
|
|
504
602
|
has_other_platform_config = any(
|
|
505
|
-
(project_root / directory).is_dir()
|
|
603
|
+
(project_root / directory).is_dir()
|
|
604
|
+
for directory in other_platform_dirs_antigravity
|
|
506
605
|
)
|
|
507
|
-
if (
|
|
606
|
+
if (
|
|
607
|
+
project_root / ".agent" / "workflows"
|
|
608
|
+
).is_dir() and not has_other_platform_config:
|
|
508
609
|
return "antigravity"
|
|
509
610
|
|
|
611
|
+
# Check for .qoder directory (Qoder-specific)
|
|
612
|
+
if (project_root / ".qoder").is_dir():
|
|
613
|
+
return "qoder"
|
|
614
|
+
|
|
510
615
|
return "claude"
|
|
511
616
|
|
|
512
617
|
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Trellis configuration reader.
|
|
4
|
+
|
|
5
|
+
Reads settings from .trellis/config.yaml with sensible defaults.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from .paths import DIR_WORKFLOW, get_repo_root
|
|
13
|
+
from .worktree import parse_simple_yaml
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Defaults
|
|
17
|
+
DEFAULT_SESSION_COMMIT_MESSAGE = "chore: record journal"
|
|
18
|
+
DEFAULT_MAX_JOURNAL_LINES = 2000
|
|
19
|
+
|
|
20
|
+
CONFIG_FILE = "config.yaml"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _get_config_path(repo_root: Path | None = None) -> Path:
|
|
24
|
+
"""Get path to config.yaml."""
|
|
25
|
+
root = repo_root or get_repo_root()
|
|
26
|
+
return root / DIR_WORKFLOW / CONFIG_FILE
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _load_config(repo_root: Path | None = None) -> dict:
|
|
30
|
+
"""Load and parse config.yaml. Returns empty dict on any error."""
|
|
31
|
+
config_file = _get_config_path(repo_root)
|
|
32
|
+
try:
|
|
33
|
+
content = config_file.read_text(encoding="utf-8")
|
|
34
|
+
return parse_simple_yaml(content)
|
|
35
|
+
except (OSError, IOError):
|
|
36
|
+
return {}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def get_session_commit_message(repo_root: Path | None = None) -> str:
|
|
40
|
+
"""Get the commit message for auto-committing session records."""
|
|
41
|
+
config = _load_config(repo_root)
|
|
42
|
+
return config.get("session_commit_message", DEFAULT_SESSION_COMMIT_MESSAGE)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def get_max_journal_lines(repo_root: Path | None = None) -> int:
|
|
46
|
+
"""Get the maximum lines per journal file."""
|
|
47
|
+
config = _load_config(repo_root)
|
|
48
|
+
value = config.get("max_journal_lines", DEFAULT_MAX_JOURNAL_LINES)
|
|
49
|
+
try:
|
|
50
|
+
return int(value)
|
|
51
|
+
except (ValueError, TypeError):
|
|
52
|
+
return DEFAULT_MAX_JOURNAL_LINES
|