Skip to content

Commit 2b577e6

Browse files
committed
feat: add TraeCn to sync/release/CI tool chain (second slice)
- sync-skills.sh: add Codex→TraeCn sync with YAML frontmatter + path rewrite - check-skills-sync.sh: add TraeCn mirror validation - check-version-consistency.sh: include TraeCn SOPIFY_VERSION in checks - check-readme-links.py: add TraeCn to VERSION_HEADERS; fix section list - .githooks/pre-commit: add TraeCn to managed_paths, is_release_relevant_file, git add - test_release_hooks.py: add TraeCn fixture and version propagation assertion
1 parent d260acf commit 2b577e6

7 files changed

Lines changed: 166 additions & 12 deletions

File tree

.githooks/pre-commit

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,14 @@ snapshot_managed_release_paths() {
2424
"Codex/Skills/EN/AGENTS.md"
2525
"Claude/Skills/CN/CLAUDE.md"
2626
"Claude/Skills/EN/CLAUDE.md"
27+
"TraeCn/Skills/CN/user_rules/sopify.md"
28+
"TraeCn/Skills/EN/user_rules/sopify.md"
2729
"Codex/Skills/CN/skills/sopify"
2830
"Codex/Skills/EN/skills/sopify"
2931
"Claude/Skills/CN/skills/sopify"
3032
"Claude/Skills/EN/skills/sopify"
33+
"TraeCn/Skills/CN/skills/sopify"
34+
"TraeCn/Skills/EN/skills/sopify"
3135
)
3236
local path
3337
local src
@@ -89,7 +93,7 @@ trap on_exit EXIT
8993
is_release_relevant_file() {
9094
local path="$1"
9195
case "$path" in
92-
runtime/*|installer/*|Codex/Skills/*|Claude/Skills/*|README.md|README.zh-CN.md|CHANGELOG.md)
96+
runtime/*|installer/*|Codex/Skills/*|Claude/Skills/*|TraeCn/Skills/*|README.md|README.zh-CN.md|CHANGELOG.md)
9397
return 0
9498
;;
9599
scripts/sopify_runtime.py|scripts/go_plan_runtime.py|scripts/model_compare_runtime.py|scripts/clarification_bridge_runtime.py|scripts/decision_bridge_runtime.py|scripts/develop_checkpoint_runtime.py|scripts/sync-runtime-assets.sh|scripts/check-runtime-smoke.sh|scripts/release-sync.sh|scripts/release-preflight.sh|scripts/sync-skills.sh|scripts/check-skills-sync.sh|scripts/check-version-consistency.sh)
@@ -160,10 +164,14 @@ git -C "$ROOT_DIR" add \
160164
Codex/Skills/EN/AGENTS.md \
161165
Claude/Skills/CN/CLAUDE.md \
162166
Claude/Skills/EN/CLAUDE.md \
167+
TraeCn/Skills/CN/user_rules/sopify.md \
168+
TraeCn/Skills/EN/user_rules/sopify.md \
163169
Codex/Skills/CN/skills/sopify \
164170
Codex/Skills/EN/skills/sopify \
165171
Claude/Skills/CN/skills/sopify \
166-
Claude/Skills/EN/skills/sopify
172+
Claude/Skills/EN/skills/sopify \
173+
TraeCn/Skills/CN/skills/sopify \
174+
TraeCn/Skills/EN/skills/sopify
167175

168176
cat >"$STATE_FILE" <<EOF
169177
RELEASE_VERSION=$RELEASE_VERSION

scripts/check-readme-links.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
ROOT / "Codex/Skills/EN/AGENTS.md",
2222
ROOT / "Claude/Skills/CN/CLAUDE.md",
2323
ROOT / "Claude/Skills/EN/CLAUDE.md",
24+
ROOT / "TraeCn/Skills/CN/user_rules/sopify.md",
25+
ROOT / "TraeCn/Skills/EN/user_rules/sopify.md",
2426
)
2527
LINK_PATTERN = re.compile(r"(?<!\!)\[[^\]]+\]\(([^)]+)\)")
2628
HEADING_PATTERN = re.compile(r"^(#{1,6})\s+(.*)$")
@@ -33,6 +35,7 @@
3335
EXPECTED_LEVEL2_SECTIONS = {
3436
README_FILES[0]: (
3537
"Why Sopify?",
38+
"What You Get After Install",
3639
"Quick Start",
3740
"Configuration",
3841
"Command Reference",
@@ -46,6 +49,7 @@
4649
),
4750
README_FILES[1]: (
4851
"为什么选择 Sopify?",
52+
"安装后你会得到什么",
4953
"快速开始",
5054
"配置说明",
5155
"命令参考",

scripts/check-skills-sync.sh

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ usage() {
99
cat <<'EOF'
1010
Usage: scripts/check-skills-sync.sh
1111
12-
Check whether Claude/* mirrors Codex/* for Sopify skills.
13-
For header files, Claude-specific config/helper paths are expected to be rewritten from ~/.codex/* to ~/.claude/*.
12+
Check whether Claude/* and TraeCn/* mirror Codex/* for Sopify skills.
13+
For header files, host-specific config/helper paths are expected to be rewritten.
1414
On mismatch, run:
1515
bash scripts/sync-skills.sh
1616
EOF
@@ -32,6 +32,22 @@ render_expected_claude_header() {
3232
"$source_file" >"$target_file"
3333
}
3434

35+
TRAE_CN_FRONTMATTER="---
36+
alwaysApply: true
37+
---"
38+
39+
render_expected_trae_cn_header() {
40+
local source_file="$1"
41+
local target_file="$2"
42+
{
43+
printf '%s\n\n' "$TRAE_CN_FRONTMATTER"
44+
sed \
45+
-e 's#~/.codex/sopify\.config\.yaml#~/.trae-cn/sopify.config.yaml#g' \
46+
-e 's#~/.codex/sopify/#~/.trae-cn/sopify/#g' \
47+
"$source_file"
48+
} >"$target_file"
49+
}
50+
3551
check_lang() {
3652
local lang="$1"
3753
local codex_dir="$ROOT_DIR/Codex/Skills/$lang"
@@ -53,13 +69,37 @@ check_lang() {
5369
fi
5470
}
5571

72+
check_trae_cn_lang() {
73+
local lang="$1"
74+
local codex_dir="$ROOT_DIR/Codex/Skills/$lang"
75+
local trae_cn_dir="$ROOT_DIR/TraeCn/Skills/$lang"
76+
local diff_file="$TMP_DIR/${lang}_trae_cn.diff"
77+
78+
render_expected_trae_cn_header "$codex_dir/AGENTS.md" "$TMP_DIR/${lang}_trae_cn.expected.md"
79+
80+
if ! diff -u "$TMP_DIR/${lang}_trae_cn.expected.md" "$trae_cn_dir/user_rules/sopify.md" >"$diff_file"; then
81+
echo "[$lang] Header file mismatch: Codex/Skills/$lang/AGENTS.md != TraeCn/Skills/$lang/user_rules/sopify.md"
82+
head -n 40 "$diff_file"
83+
status=1
84+
fi
85+
86+
if ! diff -ru -x .DS_Store -x Thumbs.db "$codex_dir/skills/sopify" "$trae_cn_dir/skills/sopify" >"$diff_file"; then
87+
echo "[$lang] Skill directory mismatch: Codex/Skills/$lang/skills/sopify != TraeCn/Skills/$lang/skills/sopify"
88+
head -n 60 "$diff_file"
89+
status=1
90+
fi
91+
}
92+
5693
check_lang "CN"
5794
check_lang "EN"
5895

96+
check_trae_cn_lang "CN"
97+
check_trae_cn_lang "EN"
98+
5999
if [[ "$status" -ne 0 ]]; then
60100
echo
61101
echo "Sync check failed. Run: bash scripts/sync-skills.sh"
62102
exit 1
63103
fi
64104

65-
echo "Sync check passed: Claude/* is aligned with Codex/*."
105+
echo "Sync check passed: Claude/* and TraeCn/* are aligned with Codex/*."

scripts/check-version-consistency.sh

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ CODEX_CN="$ROOT_DIR/Codex/Skills/CN/AGENTS.md"
1010
CODEX_EN="$ROOT_DIR/Codex/Skills/EN/AGENTS.md"
1111
CLAUDE_CN="$ROOT_DIR/Claude/Skills/CN/CLAUDE.md"
1212
CLAUDE_EN="$ROOT_DIR/Claude/Skills/EN/CLAUDE.md"
13+
TRAE_CN_CN="$ROOT_DIR/TraeCn/Skills/CN/user_rules/sopify.md"
14+
TRAE_CN_EN="$ROOT_DIR/TraeCn/Skills/EN/user_rules/sopify.md"
1315

1416
usage() {
1517
cat <<'EOF'
@@ -18,7 +20,7 @@ Usage: scripts/check-version-consistency.sh
1820
Validate version consistency across:
1921
- README.md / README.zh-CN.md version badges
2022
- Latest released version in CHANGELOG.md
21-
- SOPIFY_VERSION headers in Codex/Claude CN/EN files
23+
- SOPIFY_VERSION headers in Codex/Claude/TraeCn CN/EN files
2224
2325
Exit codes:
2426
0: all checks passed
@@ -39,6 +41,8 @@ required_files=(
3941
"$CODEX_EN"
4042
"$CLAUDE_CN"
4143
"$CLAUDE_EN"
44+
"$TRAE_CN_CN"
45+
"$TRAE_CN_EN"
4246
)
4347

4448
for file in "${required_files[@]}"; do
@@ -131,6 +135,8 @@ codex_cn_version="$(extract_sopify_version "$CODEX_CN")"
131135
codex_en_version="$(extract_sopify_version "$CODEX_EN")"
132136
claude_cn_version="$(extract_sopify_version "$CLAUDE_CN")"
133137
claude_en_version="$(extract_sopify_version "$CLAUDE_EN")"
138+
trae_cn_cn_version="$(extract_sopify_version "$TRAE_CN_CN")"
139+
trae_cn_en_version="$(extract_sopify_version "$TRAE_CN_EN")"
134140

135141
if [[ -z "$codex_cn_version" ]]; then
136142
add_error "Codex/Skills/CN/AGENTS.md: missing SOPIFY_VERSION header."
@@ -144,12 +150,18 @@ fi
144150
if [[ -z "$claude_en_version" ]]; then
145151
add_error "Claude/Skills/EN/CLAUDE.md: missing SOPIFY_VERSION header."
146152
fi
153+
if [[ -z "$trae_cn_cn_version" ]]; then
154+
add_error "TraeCn/Skills/CN/user_rules/sopify.md: missing SOPIFY_VERSION header."
155+
fi
156+
if [[ -z "$trae_cn_en_version" ]]; then
157+
add_error "TraeCn/Skills/EN/user_rules/sopify.md: missing SOPIFY_VERSION header."
158+
fi
147159

148-
header_versions=("$codex_cn_version" "$codex_en_version" "$claude_cn_version" "$claude_en_version")
160+
header_versions=("$codex_cn_version" "$codex_en_version" "$claude_cn_version" "$claude_en_version" "$trae_cn_cn_version" "$trae_cn_en_version")
149161
first_header_version="${header_versions[0]}"
150162
for version in "${header_versions[@]}"; do
151163
if [[ -n "$version" && "$version" != "$first_header_version" ]]; then
152-
add_error "Header SOPIFY_VERSION mismatch: $codex_cn_version / $codex_en_version / $claude_cn_version / $claude_en_version."
164+
add_error "Header SOPIFY_VERSION mismatch: codex=$codex_cn_version/$codex_en_version, claude=$claude_cn_version/$claude_en_version, trae-cn=$trae_cn_cn_version/$trae_cn_en_version."
153165
break
154166
fi
155167
done

scripts/sync-skills.sh

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ usage() {
77
cat <<'EOF'
88
Usage: scripts/sync-skills.sh
99
10-
Sync Sopify skill content from Codex/* to Claude/*:
10+
Sync Sopify skill content from Codex/* to Claude/* and TraeCn/*:
1111
- Codex/Skills/CN/AGENTS.md -> Claude/Skills/CN/CLAUDE.md
12-
(auto-rewrite ~/.codex/* Claude-specific config/helper paths)
12+
(auto-rewrite ~/.codex/* to ~/.claude/* paths)
1313
- Codex/Skills/EN/AGENTS.md -> Claude/Skills/EN/CLAUDE.md
14-
(auto-rewrite ~/.codex/* Claude-specific config/helper paths)
14+
(auto-rewrite ~/.codex/* to ~/.claude/* paths)
15+
- Codex/Skills/CN/AGENTS.md -> TraeCn/Skills/CN/user_rules/sopify.md
16+
(auto-rewrite ~/.codex/* to ~/.trae-cn/* paths; prepend alwaysApply frontmatter)
17+
- Codex/Skills/EN/AGENTS.md -> TraeCn/Skills/EN/user_rules/sopify.md
18+
(auto-rewrite ~/.codex/* to ~/.trae-cn/* paths; prepend alwaysApply frontmatter)
1519
- Codex/Skills/{CN,EN}/skills/sopify/* -> Claude/Skills/{CN,EN}/skills/sopify/*
20+
- Codex/Skills/{CN,EN}/skills/sopify/* -> TraeCn/Skills/{CN,EN}/skills/sopify/*
1621
EOF
1722
}
1823

@@ -31,6 +36,23 @@ render_claude_header() {
3136
"$source_file" >"$target_file"
3237
}
3338

39+
TRAE_CN_FRONTMATTER="---
40+
alwaysApply: true
41+
---"
42+
43+
render_trae_cn_header() {
44+
local source_file="$1"
45+
local target_file="$2"
46+
47+
{
48+
printf '%s\n\n' "$TRAE_CN_FRONTMATTER"
49+
sed \
50+
-e 's#~/.codex/sopify\.config\.yaml#~/.trae-cn/sopify.config.yaml#g' \
51+
-e 's#~/.codex/sopify/#~/.trae-cn/sopify/#g' \
52+
"$source_file"
53+
} >"$target_file"
54+
}
55+
3456
sync_lang() {
3557
local lang="$1"
3658
local codex_dir="$ROOT_DIR/Codex/Skills/$lang"
@@ -60,7 +82,33 @@ sync_lang() {
6082
rsync -a --delete --exclude .DS_Store --exclude Thumbs.db "$codex_dir/skills/sopify/" "$claude_dir/skills/sopify/"
6183
}
6284

85+
sync_trae_cn_lang() {
86+
local lang="$1"
87+
local codex_dir="$ROOT_DIR/Codex/Skills/$lang"
88+
local trae_cn_dir="$ROOT_DIR/TraeCn/Skills/$lang"
89+
90+
if [[ ! -f "$codex_dir/AGENTS.md" ]]; then
91+
echo "Missing source file: $codex_dir/AGENTS.md" >&2
92+
exit 1
93+
fi
94+
95+
mkdir -p "$trae_cn_dir/user_rules"
96+
97+
if [[ ! -d "$codex_dir/skills/sopify" ]]; then
98+
echo "Missing source directory: $codex_dir/skills/sopify" >&2
99+
exit 1
100+
fi
101+
102+
mkdir -p "$trae_cn_dir/skills/sopify"
103+
104+
render_trae_cn_header "$codex_dir/AGENTS.md" "$trae_cn_dir/user_rules/sopify.md"
105+
rsync -a --delete --exclude .DS_Store --exclude Thumbs.db "$codex_dir/skills/sopify/" "$trae_cn_dir/skills/sopify/"
106+
}
107+
63108
sync_lang "CN"
64109
sync_lang "EN"
65110

66-
echo "Synced Codex -> Claude for CN and EN skill bundles."
111+
sync_trae_cn_lang "CN"
112+
sync_trae_cn_lang "EN"
113+
114+
echo "Synced Codex -> Claude and Codex -> TraeCn for CN and EN skill bundles."

tests/test_check_readme_links.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,22 @@ def _minimal_agents(version: str, *, claude: bool, english: bool) -> str:
7070
)
7171

7272

73+
def _minimal_trae_cn_rules(version: str, *, english: bool) -> str:
74+
body = "Note: ~/.trae-cn/sopify/" if english else "说明:~/.trae-cn/sopify/"
75+
return textwrap.dedent(
76+
f"""\
77+
---
78+
alwaysApply: true
79+
---
80+
81+
<!-- SOPIFY_VERSION: {version} -->
82+
# Sopify Rules
83+
84+
{body}
85+
"""
86+
)
87+
88+
7389
def _configure_module(module, root: Path) -> None:
7490
readme_sections_primary = module.EXPECTED_LEVEL2_SECTIONS[module.README_FILES[0]]
7591
readme_sections_zh = module.EXPECTED_LEVEL2_SECTIONS[module.README_FILES[1]]
@@ -93,6 +109,8 @@ def _configure_module(module, root: Path) -> None:
93109
root / "Codex/Skills/EN/AGENTS.md",
94110
root / "Claude/Skills/CN/CLAUDE.md",
95111
root / "Claude/Skills/EN/CLAUDE.md",
112+
root / "TraeCn/Skills/CN/user_rules/sopify.md",
113+
root / "TraeCn/Skills/EN/user_rules/sopify.md",
96114
)
97115
module.EXPECTED_LEVEL2_SECTIONS = {
98116
module.README_FILES[0]: readme_sections_primary,
@@ -130,6 +148,8 @@ def _init_fixture(root: Path, module, *, broken_workflow_link: bool = False, reo
130148
_write(root / "Codex/Skills/EN/AGENTS.md", _minimal_agents(VERSION, claude=False, english=True))
131149
_write(root / "Claude/Skills/CN/CLAUDE.md", _minimal_agents(VERSION, claude=True, english=False))
132150
_write(root / "Claude/Skills/EN/CLAUDE.md", _minimal_agents(VERSION, claude=True, english=True))
151+
_write(root / "TraeCn/Skills/CN/user_rules/sopify.md", _minimal_trae_cn_rules(VERSION, english=False))
152+
_write(root / "TraeCn/Skills/EN/user_rules/sopify.md", _minimal_trae_cn_rules(VERSION, english=True))
133153

134154
_write(
135155
root / "README.md",

tests/test_release_hooks.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ def _minimal_agents(version: str, *, claude: bool, english: bool) -> str:
9999
)
100100

101101

102+
def _minimal_trae_cn_rules(version: str, *, english: bool) -> str:
103+
body = "Note: ~/.trae-cn/sopify/" if english else "说明:~/.trae-cn/sopify/"
104+
return textwrap.dedent(
105+
f"""\
106+
---
107+
alwaysApply: true
108+
---
109+
110+
<!-- SOPIFY_VERSION: {version} -->
111+
# Sopify Rules
112+
113+
{body}
114+
"""
115+
)
116+
117+
102118
def _unreleased_body(changelog_text: str) -> str:
103119
start = changelog_text.index("## [Unreleased]") + len("## [Unreleased]")
104120
end = changelog_text.find("\n## [", start)
@@ -148,6 +164,11 @@ def _init_release_hook_fixture(root: Path, *, missing_claude_targets: bool = Fal
148164
_write(root / "Claude/Skills/CN/skills/sopify/SKILL.md", "# skill\n")
149165
_write(root / "Claude/Skills/EN/skills/sopify/SKILL.md", "# skill\n")
150166

167+
_write(root / "TraeCn/Skills/CN/user_rules/sopify.md", _minimal_trae_cn_rules(old_version, english=False))
168+
_write(root / "TraeCn/Skills/EN/user_rules/sopify.md", _minimal_trae_cn_rules(old_version, english=True))
169+
_write(root / "TraeCn/Skills/CN/skills/sopify/SKILL.md", "# skill\n")
170+
_write(root / "TraeCn/Skills/EN/skills/sopify/SKILL.md", "# skill\n")
171+
151172
_write(root / "runtime/gate.py", "print('baseline')\n")
152173
_write(root / "tests/test_runtime_gate.py", "print('baseline test')\n")
153174

@@ -334,6 +355,7 @@ def test_release_sync_auto_drafts_unreleased_before_version_bump(self) -> None:
334355
self.assertIn("badge/version-2026--03--21.010203-orange.svg", (root / "README.md").read_text(encoding="utf-8"))
335356
self.assertIn("<!-- SOPIFY_VERSION: 2026-03-21.010203 -->", (root / "Codex/Skills/CN/AGENTS.md").read_text(encoding="utf-8"))
336357
self.assertIn("<!-- SOPIFY_VERSION: 2026-03-21.010203 -->", (root / "Claude/Skills/CN/CLAUDE.md").read_text(encoding="utf-8"))
358+
self.assertIn("<!-- SOPIFY_VERSION: 2026-03-21.010203 -->", (root / "TraeCn/Skills/CN/user_rules/sopify.md").read_text(encoding="utf-8"))
337359

338360
def test_release_draft_only_renders_non_empty_sections(self) -> None:
339361
with tempfile.TemporaryDirectory() as temp_dir:

0 commit comments

Comments
 (0)