@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.
Files changed (107) hide show
  1. package/README.md +74 -130
  2. package/dist/cli/index.js +1 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +30 -2
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +11 -39
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/configurators/index.d.ts.map +1 -1
  12. package/dist/configurators/index.js +15 -3
  13. package/dist/configurators/index.js.map +1 -1
  14. package/dist/configurators/kilo.d.ts +1 -1
  15. package/dist/configurators/kilo.d.ts.map +1 -1
  16. package/dist/configurators/kilo.js +2 -1
  17. package/dist/configurators/kilo.js.map +1 -1
  18. package/dist/configurators/qoder.d.ts +8 -0
  19. package/dist/configurators/qoder.d.ts.map +1 -0
  20. package/dist/configurators/qoder.js +52 -0
  21. package/dist/configurators/qoder.js.map +1 -0
  22. package/dist/configurators/workflow.d.ts.map +1 -1
  23. package/dist/configurators/workflow.js +3 -1
  24. package/dist/configurators/workflow.js.map +1 -1
  25. package/dist/migrations/manifests/0.3.2.json +9 -0
  26. package/dist/migrations/manifests/0.3.3.json +9 -0
  27. package/dist/migrations/manifests/0.3.4.json +21 -0
  28. package/dist/migrations/manifests/0.3.5.json +9 -0
  29. package/dist/templates/claude/commands/trellis/record-session.md +12 -16
  30. package/dist/templates/codex/skills/record-session/SKILL.md +13 -17
  31. package/dist/templates/cursor/commands/trellis-record-session.md +12 -16
  32. package/dist/templates/extract.d.ts +7 -0
  33. package/dist/templates/extract.d.ts.map +1 -1
  34. package/dist/templates/extract.js +13 -0
  35. package/dist/templates/extract.js.map +1 -1
  36. package/dist/templates/gemini/commands/trellis/record-session.toml +12 -16
  37. package/dist/templates/iflow/commands/trellis/record-session.md +12 -16
  38. package/dist/templates/iflow/hooks/session-start.py +1 -0
  39. package/dist/templates/kilo/commands/trellis/record-session.md +12 -16
  40. package/dist/templates/kilo/index.d.ts +3 -3
  41. package/dist/templates/kilo/index.d.ts.map +1 -1
  42. package/dist/templates/kilo/index.js +7 -7
  43. package/dist/templates/kilo/index.js.map +1 -1
  44. package/dist/templates/kilo/workflows/before-backend-dev.md +13 -0
  45. package/dist/templates/kilo/workflows/before-frontend-dev.md +13 -0
  46. package/dist/templates/kilo/workflows/brainstorm.md +474 -0
  47. package/dist/templates/kilo/workflows/break-loop.md +125 -0
  48. package/dist/templates/kilo/workflows/check-backend.md +13 -0
  49. package/dist/templates/kilo/workflows/check-cross-layer.md +153 -0
  50. package/dist/templates/kilo/workflows/check-frontend.md +13 -0
  51. package/dist/templates/kilo/workflows/create-command.md +152 -0
  52. package/dist/templates/kilo/workflows/finish-work.md +129 -0
  53. package/dist/templates/kilo/workflows/integrate-skill.md +219 -0
  54. package/dist/templates/kilo/workflows/onboard.md +358 -0
  55. package/dist/templates/kilo/workflows/parallel.md +194 -0
  56. package/dist/templates/kilo/workflows/record-session.md +58 -0
  57. package/dist/templates/kilo/workflows/start.md +321 -0
  58. package/dist/templates/kilo/workflows/update-spec.md +285 -0
  59. package/dist/templates/kiro/skills/record-session/SKILL.md +13 -17
  60. package/dist/templates/opencode/commands/trellis/record-session.md +12 -16
  61. package/dist/templates/qoder/index.d.ts +18 -0
  62. package/dist/templates/qoder/index.d.ts.map +1 -0
  63. package/dist/templates/qoder/index.js +40 -0
  64. package/dist/templates/qoder/index.js.map +1 -0
  65. package/dist/templates/qoder/skills/before-backend-dev/SKILL.md +18 -0
  66. package/dist/templates/qoder/skills/before-frontend-dev/SKILL.md +18 -0
  67. package/dist/templates/qoder/skills/brainstorm/SKILL.md +479 -0
  68. package/dist/templates/qoder/skills/break-loop/SKILL.md +130 -0
  69. package/dist/templates/qoder/skills/check-backend/SKILL.md +18 -0
  70. package/dist/templates/qoder/skills/check-cross-layer/SKILL.md +158 -0
  71. package/dist/templates/qoder/skills/check-frontend/SKILL.md +18 -0
  72. package/dist/templates/qoder/skills/create-command/SKILL.md +101 -0
  73. package/dist/templates/qoder/skills/finish-work/SKILL.md +134 -0
  74. package/dist/templates/qoder/skills/integrate-skill/SKILL.md +221 -0
  75. package/dist/templates/qoder/skills/onboard/SKILL.md +363 -0
  76. package/dist/templates/qoder/skills/record-session/SKILL.md +63 -0
  77. package/dist/templates/qoder/skills/start/SKILL.md +326 -0
  78. package/dist/templates/qoder/skills/update-spec/SKILL.md +290 -0
  79. package/dist/templates/trellis/config.yaml +15 -0
  80. package/dist/templates/trellis/index.d.ts +3 -0
  81. package/dist/templates/trellis/index.d.ts.map +1 -1
  82. package/dist/templates/trellis/index.js +4 -0
  83. package/dist/templates/trellis/index.js.map +1 -1
  84. package/dist/templates/trellis/scripts/add_session.py +52 -21
  85. package/dist/templates/trellis/scripts/common/__init__.py +3 -1
  86. package/dist/templates/trellis/scripts/common/cli_adapter.py +125 -20
  87. package/dist/templates/trellis/scripts/common/config.py +52 -0
  88. package/dist/templates/trellis/scripts/common/git_context.py +121 -11
  89. package/dist/templates/trellis/scripts/multi_agent/plan.py +4 -1
  90. package/dist/templates/trellis/scripts/multi_agent/start.py +5 -1
  91. package/dist/templates/trellis/scripts/task.py +26 -0
  92. package/dist/types/ai-tools.d.ts +3 -3
  93. package/dist/types/ai-tools.d.ts.map +1 -1
  94. package/dist/types/ai-tools.js +8 -0
  95. package/dist/types/ai-tools.js.map +1 -1
  96. package/dist/utils/proxy.d.ts +25 -0
  97. package/dist/utils/proxy.d.ts.map +1 -0
  98. package/dist/utils/proxy.js +60 -0
  99. package/dist/utils/proxy.js.map +1 -0
  100. package/dist/utils/template-fetcher.d.ts +11 -2
  101. package/dist/utils/template-fetcher.d.ts.map +1 -1
  102. package/dist/utils/template-fetcher.js +92 -19
  103. package/dist/utils/template-fetcher.js.map +1 -1
  104. package/dist/utils/template-hash.d.ts.map +1 -1
  105. package/dist/utils/template-hash.js +1 -0
  106. package/dist/utils/template-hash.js.map +1 -1
  107. package/package.json +10 -9
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,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;AAED,gCAAgC;AAChC,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,qBAAqB,CAAC,CAAC;AAE/D,0BAA0B;AAC1B,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC,4BAA4B,CAAC,CAAC;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,6BAA6B,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC,4BAA4B,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC,4BAA4B,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AAEnE,+BAA+B;AAC/B,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC,iCAAiC,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC5E,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC,gCAAgC,CAAC,CAAC;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAC5C,kCAAkC,CACnC,CAAC;AACF,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC,6BAA6B,CAAC,CAAC;AAE1E,wBAAwB;AACxB,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC,0BAA0B,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,mBAAmB,GAAG,YAAY,CAAC,2BAA2B,CAAC,CAAC;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC,iBAAiB,CAAC,CAAC;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAC;AACvE,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAC;AACvE,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAC/C,6BAA6B,CAC9B,CAAC;AAEF,2BAA2B;AAC3B,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC,wBAAwB,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAChD,+BAA+B,CAChC,CAAC;AACF,MAAM,CAAC,MAAM,4BAA4B,GAAG,YAAY,CACtD,qCAAqC,CACtC,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,oCAAoC,GAAG,YAAY,CAC9D,6CAA6C,CAC9C,CAAC;AACF,MAAM,CAAC,MAAM,kCAAkC,GAAG,YAAY,CAC5D,2CAA2C,CAC5C,CAAC;AAEF,iCAAiC;AACjC,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAC/C,mCAAmC,CACpC,CAAC;AACF,MAAM,CAAC,MAAM,mCAAmC,GAAG,YAAY,CAC7D,6CAA6C,CAC9C,CAAC;AACF,MAAM,CAAC,MAAM,sCAAsC,GAAG,YAAY,CAChE,gDAAgD,CACjD,CAAC;AAEF,sBAAsB;AACtB,MAAM,CAAC,MAAM,kBAAkB,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;AAC9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAClE,MAAM,CAAC,MAAM,iBAAiB,GAAG,YAAY,CAAC,eAAe,CAAC,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,eAAe;IACf,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IAExC,SAAS;IACT,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,cAAc,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC;IAE5C,cAAc;IACd,OAAO,CAAC,GAAG,CAAC,yBAAyB,EAAE,cAAc,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,eAAe,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,0BAA0B,EAAE,kBAAkB,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC;IAEnD,OAAO;IACP,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;IAE1D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAExC,KAAK;IACL,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;IACtC,KAAK,CAAC,GAAG,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC;IACxD,KAAK,CAAC,GAAG,CAAC,0BAA0B,EAAE,4BAA4B,CAAC,CAAC;IAEpE,WAAW;IACX,KAAK,CAAC,GAAG,CAAC,mBAAmB,EAAE,iBAAiB,CAAC,CAAC;IAClD,KAAK,CAAC,GAAG,CACP,kCAAkC,EAClC,oCAAoC,CACrC,CAAC;IACF,KAAK,CAAC,GAAG,CACP,gCAAgC,EAChC,kCAAkC,CACnC,CAAC;IAEF,WAAW;IACX,KAAK,CAAC,GAAG,CAAC,wBAAwB,EAAE,qBAAqB,CAAC,CAAC;IAC3D,KAAK,CAAC,GAAG,CACP,kCAAkC,EAClC,mCAAmC,CACpC,CAAC;IACF,KAAK,CAAC,GAAG,CACP,qCAAqC,EACrC,sCAAsC,CACvC,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC"}
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(dev_dir: Path, num: int, developer: str, today: str) -> Path:
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 ~{MAX_LINES} lines)
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 > MAX_LINES:
354
+ if current_lines + content_lines > max_lines:
334
355
  target_num = current_num + 1
335
- print(f"[!] Exceeds {MAX_LINES} lines, creating {FILE_JOURNAL_PREFIX}{target_num}.md", file=sys.stderr)
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(args.title, args.commit, args.summary, extra_content)
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 Antigravity interfaces.
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["claude", "opencode", "cursor", "iflow", "codex", "kilo", "kiro", "gemini", "antigravity"]
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 '.agent')
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 .agent)
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 == "antigravity":
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 self.get_config_dir(project_root) / "commands" / f"trellis-{filename}"
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 OpenCode support CLI agent execution.
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', or 'antigravity')
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 ("claude", "opencode", "cursor", "iflow", "codex", "kilo", "kiro", "gemini", "antigravity"):
430
- raise ValueError(f"Unsupported platform: {platform} (must be 'claude', 'opencode', 'cursor', 'iflow', 'codex', 'kilo', 'kiro', 'gemini', or 'antigravity')")
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. Defaultclaude
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 'antigravity')
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 ("claude", "opencode", "cursor", "iflow", "codex", "kilo", "kiro", "gemini", "antigravity"):
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 = (".claude", ".cursor", ".iflow", ".opencode", ".kilocode", ".kiro", ".gemini", ".agent")
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 = (".claude", ".cursor", ".iflow", ".opencode", ".agents", ".kilocode", ".gemini", ".agent")
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 = (".claude", ".cursor", ".iflow", ".opencode", ".agents", ".kilocode", ".kiro")
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() for directory in other_platform_dirs_antigravity
603
+ (project_root / directory).is_dir()
604
+ for directory in other_platform_dirs_antigravity
506
605
  )
507
- if (project_root / ".agent" / "workflows").is_dir() and not has_other_platform_config:
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