Skip to content

Commit 289553c

Browse files
committed
feat(trellis): 升级0.5.13
1 parent 1e407e9 commit 289553c

12 files changed

Lines changed: 873 additions & 221 deletions

File tree

.agents/skills/trellis-start/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Identity, git status, current task, active tasks, journal location.
1616
python3 ./.trellis/scripts/get_context.py
1717
```
1818

19+
If this output includes a line beginning `Trellis update available:`, copy the full line verbatim when summarizing session context. Do not shorten operational command hints.
20+
1921
## Step 2: Workflow overview
2022
Phase Index + skill routing table + DO-NOT-skip rules.
2123

.claude/settings.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{
1111
"type": "command",
1212
"command": "python3 .claude/hooks/session-start.py",
13-
"timeout": 10
13+
"timeout": 30
1414
}
1515
]
1616
},
@@ -20,7 +20,7 @@
2020
{
2121
"type": "command",
2222
"command": "python3 .claude/hooks/session-start.py",
23-
"timeout": 10
23+
"timeout": 30
2424
}
2525
]
2626
},
@@ -30,7 +30,7 @@
3030
{
3131
"type": "command",
3232
"command": "python3 .claude/hooks/session-start.py",
33-
"timeout": 10
33+
"timeout": 30
3434
}
3535
]
3636
}
@@ -63,7 +63,7 @@
6363
{
6464
"type": "command",
6565
"command": "python3 .claude/hooks/inject-workflow-state.py",
66-
"timeout": 5
66+
"timeout": 15
6767
}
6868
]
6969
}

.codex/hooks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
{
77
"type": "command",
88
"command": "python3 .codex/hooks/inject-workflow-state.py",
9-
"timeout": 5
9+
"timeout": 15
1010
}
1111
]
1212
}

.trellis/.template-hashes.json

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"__version": 2,
33
"hashes": {
44
"AGENTS.md": "3dcc8f780ab6e64ddf2e0b3d747f3ed4f682b09a628f5455a6e513ca6d9f7494",
5-
".trellis/config.yaml": "7ae2d8a7e73ebccd35340fdad5272142db4f7d5f3c56622e4a38e73f83c31685",
5+
".trellis/config.yaml": "5c9207418cecc390e9d86d589b4183b831f76697d92fb42fefd5221cd8772e51",
66
".trellis/scripts/__init__.py": "1242be5b972094c2e141aecbe81a4efd478f6534e3d5e28306374e6a18fcf46c",
7-
".trellis/scripts/add_session.py": "a97a6c88ff7def8045a5dffa5c698a823392d7f73c1641e8a0c08db0168bd913",
7+
".trellis/scripts/add_session.py": "6e406a0a9f32d4a50b1b5ca8115cbd06c359011f0e166c41dc5fab34698a4006",
88
".trellis/scripts/common/__init__.py": "3d5e9347141f0296319a5beb29d69ae714c5a474b9078caeb3edd7c5f6562e22",
99
".trellis/scripts/common/__pycache__/__init__.cpython-312.pyc": "5604a432ba0eea8d36f493ab1832a7d30e05fcc66bc5b0cecbee63e89e04247f",
1010
".trellis/scripts/common/__pycache__/active_task.cpython-312.pyc": "38d75d92c2d7aef708f13d1de329ca688147f893449b4991316b639b9577da00",
@@ -20,18 +20,18 @@
2020
".trellis/scripts/common/__pycache__/workflow_phase.cpython-312.pyc": "537e161720151f8dcd68200abb15fd472698f5914f702e7bef2599cf4f7e4dd5",
2121
".trellis/scripts/common/active_task.py": "6c88ed40ef7289bca0f6d2ecba0f8b8aef46cd58788080fbeeea88de138a431f",
2222
".trellis/scripts/common/cli_adapter.py": "cd844d1e84b1a09b373b3a7609e4d5606ee9d4825154c002cc9bb3f54c8e2fb9",
23-
".trellis/scripts/common/config.py": "671a3591f97b75ec19f25814d2ee3f7e9b38e048f6f67442519fe0715c454eeb",
23+
".trellis/scripts/common/config.py": "25c5a53ad20d6909be5209222e4208a84528805316a4d78350529459a364edb1",
2424
".trellis/scripts/common/developer.py": "f5f833123abe68890171b4da825a324216d24913f6b5ad9245afc556424ffd7b",
2525
".trellis/scripts/common/git.py": "e14817be7de122d3a106f509c2825aeb9669d962ba73ba241642d2931cfdf1d6",
2626
".trellis/scripts/common/git_context.py": "fa30ced454f1a91ffc9f8b2abeb32225e3447cbdc90bad783797374eba07265d",
2727
".trellis/scripts/common/io.py": "6480b181f2bc505323b28ed7a66963d7b7edc96251e83b4c8e7a45907cc721c8",
2828
".trellis/scripts/common/log.py": "471df6895cfac80f995edebbf9974f6b7440634b7a688f28b8331c868bc0f3cf",
2929
".trellis/scripts/common/packages_context.py": "efe158d7c99c2268851d0216fbb08de22836e418a8dbeb73575b8cc249eed7b7",
3030
".trellis/scripts/common/paths.py": "05898ef136cc7c4d861b05fbf2b16d53ddd3e6f311a231d4fcfcb81bde7c45ee",
31-
".trellis/scripts/common/session_context.py": "02e8d8209c2b88efeb83c9f1a3edf20d6344ceda5fcb9da53a3eb24fbfb47b17",
31+
".trellis/scripts/common/session_context.py": "c91cf213025e5e4ad2f56bb6f570ef43d35430fc8a863be311d3e5f8f32ef652",
3232
".trellis/scripts/common/task_context.py": "1c16a7fa82d363010d0d0ebdc038296ae1552bf6e90214787d707f49567bc159",
3333
".trellis/scripts/common/task_queue.py": "0be61f713462b1fe4574927c82fc4704e678afe72dcb9813543aedf2f9e9e0c5",
34-
".trellis/scripts/common/task_store.py": "e3802a822dcd0a8005bac6ffe50af196944c2a42d56d70e68c622aaf9b1156e2",
34+
".trellis/scripts/common/task_store.py": "ca1e7619503606d89f9093dfe5c6140587ce237e92f0aefe5efea5aebb50d255",
3535
".trellis/scripts/common/task_utils.py": "f5ef4af87ba3e11d8b19630c0c96d009de1811fc9be56c2027a9c96e21ed103e",
3636
".trellis/scripts/common/tasks.py": "4436a8b0b53c270a35989e26d9dbd92669408c6562d88c02083a404562da85fe",
3737
".trellis/scripts/common/types.py": "9962081cc2608fb9d1deb32c6880e336f62cdca6b338e7ae813304701e155ee9",
@@ -41,7 +41,7 @@
4141
".trellis/scripts/hooks/linear_sync.py": "e09cc4ce4699aada908808718698f33f705a3edf55c4dcf8f777ad892f80ca79",
4242
".trellis/scripts/init_developer.py": "f9e6c0d882406e81c8cd6b1c5abb204b0befc0069ff89cf650cd536a80f8c60e",
4343
".trellis/scripts/task.py": "40abdd46f5c2b6837610429a38eef50f1fc783fb1852dc4f52a891205e42ab04",
44-
".trellis/workflow.md": "ebc2b5fc37611770c727baee6bdec9dc54873e0fa4dcd2ef6f2a2e54840e4ef3",
44+
".trellis/workflow.md": "f7f888cf61afe4b4903c90046c701a6c115ed80d39c50da8fd2ac437922175b6",
4545
".claude/agents/trellis-check.md": "d1359521f7f3e9bbbf10e856a3e0912c423581a88ac188b1f0523d6357962909",
4646
".claude/agents/trellis-implement.md": "61155f06ccdd26e5aeb8171face2a029a8fb77a3d1a2b277442ded186853446c",
4747
".claude/agents/trellis-research.md": "f82244b2a88a1f77b09813f58a7fdf506f8e9603a5c34b3abe6e170f73ab68a8",
@@ -64,7 +64,7 @@
6464
".claude/m/commands/plan-achieve.md": "478e35413ae679f47bcb5f879be4f69b975531e8219128c0a1ebd9e2e2dcc534",
6565
".claude/m/commands/plan-next.md": "f3893c761d5ecd382186e0587be309914716791876dfed89e1f60fc35599fe83",
6666
".claude/m/commands/plan-save.md": "a42e48aaa620a21f357c0e6f5ff00a4bdd1c53adedc16f58c60e9cc3e4b0fde6",
67-
".claude/settings.json": "4defe9eae17b3101dae357179503683d868859e570931a7d3181e4ab10d82a9f",
67+
".claude/settings.json": "d13cd05659281a287d7f50c7e25eb6a89c2a6597773511bd6885538acced2855",
6868
".claude/settings.json.new": "27ad116000465c63b2c572e05bbdcf3a3c340614cc9cb62fb5c112b29f0f96bc",
6969
".claude/skills/openspec-apply-change/SKILL.md": "d8d5aac6edf34cb257c7f07c17128a3407975e5b24731997db0d506b5cbada98",
7070
".claude/skills/openspec-archive-change/SKILL.md": "b56f0ffbf2ed088582ebc07f88b3aa4b9fdb9f1c7b359e4c762f84347ea7132a",
@@ -110,7 +110,7 @@
110110
".codex/config.toml": "bb5a62ce51a4357b825e2a77c9a0d3332b108bb469d3b06b275604ccbccd4320",
111111
".codex/hooks/inject-workflow-state.py": "0f5f983be0fbf6241f55f5d4a1838064322178a2b3efb227027c20d26f2354d2",
112112
".codex/hooks/session-start.py": "dc90aac812aac4f0243709be337369b91e2561465f0943c04d982a1b60b58ba1",
113-
".codex/hooks.json": "68f84915798762ac6159ee2af107d54dcf72ac63483b4216079dd829da3760b2",
113+
".codex/hooks.json": "0c80314cba548a01a9b4a7141fbcb4ab9228ace8397df98ee3a365d0491a77d0",
114114
".codex/skills/openspec-apply-change/SKILL.md": "d8d5aac6edf34cb257c7f07c17128a3407975e5b24731997db0d506b5cbada98",
115115
".codex/skills/openspec-archive-change/SKILL.md": "b56f0ffbf2ed088582ebc07f88b3aa4b9fdb9f1c7b359e4c762f84347ea7132a",
116116
".codex/skills/openspec-bulk-archive-change/SKILL.md": "7a185905d8fbb59cf3a4895ea1dd48bf55421781eea37b50c92c77f8e89556a1",
@@ -159,6 +159,7 @@
159159
".agents/skills/trellis-meta/references/platform-files/skills-and-commands.md": "85435eb8bb6921283575bca51268fc534c22fd3ca33782e841ee5c76140ae48f",
160160
".agents/skills/trellis-update-spec/SKILL.md": "003ce08a3404aeb50998029392c4d4e57b626edf526d3ebd585032bb92dcbb96",
161161
".trellis/scripts/common/trellis_config.py": "0839dcf90ebbd77712c276930a89335b3313927051650c91d220fb51ca2a6a3c",
162-
".agents/skills/trellis-start/SKILL.md": "ca79cba81112f68a6997c13ef8b411e9ca88429923ec17b71e4df69faf58d676"
162+
".agents/skills/trellis-start/SKILL.md": "a88faaac9fe1b9fa7441473a72ff88ead0022504eeb38492ecef85db75a559e7",
163+
".trellis/scripts/common/safe_commit.py": "84812d4eac7eba8f851fb10cacb5d4838bf33d1d23b7263bd295332bc0cdbe68"
163164
}
164165
}

.trellis/.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.9
1+
0.5.13

.trellis/config.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,24 @@ session_commit_message: "chore: record journal"
1414
# Maximum lines per journal file before rotating to a new one
1515
max_journal_lines: 2000
1616

17+
#-------------------------------------------------------------------------------
18+
# Session Auto-Commit
19+
#-------------------------------------------------------------------------------
20+
21+
# Auto-commit behavior for session journal + task archive operations.
22+
# - true (default): scripts auto-stage and auto-commit journal / task changes
23+
# after add_session.py / task.py archive runs.
24+
# - false: scripts do not touch git. Files (journal-*.md, task archive moves)
25+
# are still written to disk; you decide whether to git add / commit.
26+
#
27+
# Use `false` if your project's .gitignore intentionally excludes `.trellis/`
28+
# and you want session data kept local-only, or if you prefer to review
29+
# staged changes manually before each commit.
30+
#
31+
# Accepts: true / false / yes / no / 1 / 0 / on / off (case-insensitive).
32+
#
33+
# session_auto_commit: true
34+
1735
#-------------------------------------------------------------------------------
1836
# Task Lifecycle Hooks
1937
#-------------------------------------------------------------------------------

.trellis/scripts/add_session.py

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import argparse
2525
import re
26-
import subprocess
2726
import sys
2827
from datetime import datetime
2928
from pathlib import Path
@@ -37,9 +36,15 @@
3736
)
3837
from common.developer import ensure_developer
3938
from common.git import run_git
39+
from common.safe_commit import (
40+
print_gitignore_warning,
41+
safe_git_add,
42+
safe_trellis_paths_to_add,
43+
)
4044
from common.tasks import load_task
4145
from common.config import (
4246
get_packages,
47+
get_session_auto_commit,
4348
get_session_commit_message,
4449
get_max_journal_lines,
4550
is_monorepo,
@@ -314,36 +319,57 @@ def update_index(
314319
# =============================================================================
315320

316321
def _auto_commit_workspace(repo_root: Path) -> None:
317-
"""Stage .trellis/workspace and .trellis/tasks, then commit with a configured message."""
322+
"""Stage Trellis-owned workspace + task paths and commit.
323+
324+
Path scope is restricted to specific products (journal files, index.md,
325+
active task dirs, the archive subtree). We never `git add` the whole
326+
`.trellis/` tree, and if `.gitignore` blocks the specific paths we
327+
warn + skip — never retry with ``-f``.
328+
329+
Honors ``session_auto_commit`` in ``.trellis/config.yaml``: when set to
330+
``false``, this function returns immediately without touching git
331+
(journal/index files are still written to disk by the caller).
332+
"""
333+
if not get_session_auto_commit(repo_root):
334+
print(
335+
"[OK] session_auto_commit: false — skipping git stage/commit.",
336+
file=sys.stderr,
337+
)
338+
return
339+
318340
commit_msg = get_session_commit_message(repo_root)
319-
add_result = subprocess.run(
320-
["git", "add", "-A", ".trellis/workspace", ".trellis/tasks"],
321-
cwd=repo_root,
322-
capture_output=True,
323-
text=True,
324-
)
325-
if add_result.returncode != 0:
326-
print(f"[WARN] git add failed (exit {add_result.returncode}): {add_result.stderr.strip()}", file=sys.stderr)
327-
print("[WARN] Please commit .trellis/ changes manually: git add .trellis && git commit", file=sys.stderr)
341+
paths = safe_trellis_paths_to_add(repo_root)
342+
if not paths:
343+
print("[OK] No workspace changes to commit.", file=sys.stderr)
344+
return
345+
346+
success, _, err = safe_git_add(paths, repo_root)
347+
if not success:
348+
if err and "ignored by" in err.lower():
349+
print_gitignore_warning(paths)
350+
else:
351+
print(
352+
f"[WARN] git add failed: {err.strip() if err else 'unknown error'}",
353+
file=sys.stderr,
354+
)
328355
return
329-
# Check if there are staged changes
330-
result = subprocess.run(
331-
["git", "diff", "--cached", "--quiet", "--", ".trellis/workspace", ".trellis/tasks"],
332-
cwd=repo_root,
356+
357+
# Check if there are staged changes for the paths we just staged.
358+
rc, _, _ = run_git(
359+
["diff", "--cached", "--quiet", "--", *paths], cwd=repo_root
333360
)
334-
if result.returncode == 0:
361+
if rc == 0:
335362
print("[OK] No workspace changes to commit.", file=sys.stderr)
336363
return
337-
commit_result = subprocess.run(
338-
["git", "commit", "-m", commit_msg],
339-
cwd=repo_root,
340-
capture_output=True,
341-
text=True,
342-
)
343-
if commit_result.returncode == 0:
364+
365+
rc, _, commit_err = run_git(["commit", "-m", commit_msg], cwd=repo_root)
366+
if rc == 0:
344367
print(f"[OK] Auto-committed: {commit_msg}", file=sys.stderr)
345368
else:
346-
print(f"[WARN] Auto-commit failed: {commit_result.stderr.strip()}", file=sys.stderr)
369+
print(
370+
f"[WARN] Auto-commit failed: {commit_err.strip()}",
371+
file=sys.stderr,
372+
)
347373

348374

349375
def add_session(

.trellis/scripts/common/config.py

100644100755
Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ def _unquote(s: str) -> str:
3636
return s
3737

3838

39+
def _strip_inline_comment(value: str) -> str:
40+
"""Strip ` # …` inline comments while preserving `#` inside quoted strings.
41+
42+
YAML treats ` #` (space-hash) as a comment opener; bare `#` inside a token
43+
is part of the value. Quoted strings are immune.
44+
45+
Mirrors :func:`common.trellis_config._strip_inline_comment` so both
46+
parsers handle ``key: value # comment`` identically.
47+
"""
48+
in_quote: str | None = None
49+
for idx, ch in enumerate(value):
50+
if in_quote:
51+
if ch == in_quote:
52+
in_quote = None
53+
continue
54+
if ch in ('"', "'"):
55+
in_quote = ch
56+
continue
57+
if ch == "#" and (idx == 0 or value[idx - 1].isspace()):
58+
return value[:idx]
59+
return value
60+
61+
3962
def parse_simple_yaml(content: str) -> dict:
4063
"""Parse simple YAML with nested dict support (no dependencies).
4164
@@ -93,7 +116,8 @@ def _parse_yaml_block(
93116
elif ":" in stripped:
94117
key, _, value = stripped.partition(":")
95118
key = key.strip()
96-
value = _unquote(value.strip())
119+
value = _strip_inline_comment(value).strip()
120+
value = _unquote(value)
97121
current_list = None
98122

99123
if value:
@@ -142,6 +166,7 @@ def _next_content_line(lines: list[str], start: int) -> tuple[int, str]:
142166
# Defaults
143167
DEFAULT_SESSION_COMMIT_MESSAGE = "chore: record journal"
144168
DEFAULT_MAX_JOURNAL_LINES = 2000
169+
DEFAULT_SESSION_AUTO_COMMIT = True
145170

146171
CONFIG_FILE = "config.yaml"
147172

@@ -187,6 +212,37 @@ def get_max_journal_lines(repo_root: Path | None = None) -> int:
187212
return DEFAULT_MAX_JOURNAL_LINES
188213

189214

215+
def get_session_auto_commit(repo_root: Path | None = None) -> bool:
216+
"""Whether scripts should auto-stage + auto-commit session/task changes.
217+
218+
Governs both ``add_session.py:_auto_commit_workspace`` and
219+
``task_store.py:_auto_commit_archive``.
220+
221+
Default: ``True`` (existing behavior — auto-stage + auto-commit).
222+
Set ``session_auto_commit: false`` in ``.trellis/config.yaml`` to skip
223+
auto-staging entirely; the journal/archive files are still written to
224+
disk, but the user manages ``git add`` / ``git commit`` themselves.
225+
226+
Accepts native YAML booleans (``true`` / ``false``) and the string
227+
aliases ``true / false / yes / no / 1 / 0 / on / off`` (case-insensitive).
228+
Invalid values fall back to ``True`` with a stderr warning.
229+
"""
230+
config = _load_config(repo_root)
231+
raw = config.get("session_auto_commit", DEFAULT_SESSION_AUTO_COMMIT)
232+
if isinstance(raw, bool):
233+
return raw
234+
s = str(raw).strip().lower()
235+
if s in ("true", "yes", "1", "on"):
236+
return True
237+
if s in ("false", "no", "0", "off"):
238+
return False
239+
print(
240+
f"[WARN] invalid session_auto_commit value: {raw!r}; using true (default)",
241+
file=sys.stderr,
242+
)
243+
return DEFAULT_SESSION_AUTO_COMMIT
244+
245+
190246
def get_hooks(event: str, repo_root: Path | None = None) -> list[str]:
191247
"""Get hook commands for a lifecycle event.
192248

0 commit comments

Comments
 (0)