@seanyao/roll 2026.505.1 → 2026.505.3
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 +4 -4
- package/bin/roll +117 -18
- package/conventions/templates/cli/CLAUDE.md +3 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,8 +48,7 @@ roll setup
|
|
|
48
48
|
To update:
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
|
|
52
|
-
roll setup
|
|
51
|
+
roll update
|
|
53
52
|
```
|
|
54
53
|
|
|
55
54
|
> **For contributors** (working on roll itself): `git clone https://github.com/seanyao/roll.git && cd roll && ./install.sh`
|
|
@@ -65,6 +64,7 @@ Unified behavioral conventions for Claude Code / Gemini CLI / Cursor / Codex —
|
|
|
65
64
|
| Command | Description |
|
|
66
65
|
|---------|-------------|
|
|
67
66
|
| `roll setup` | First-time install on this machine, or re-sync after editing `~/.roll/config.yaml` (use `--force` to overwrite local cache) |
|
|
67
|
+
| `roll update` | One-step upgrade: `npm install -g @seanyao/roll@latest` + re-sync via `roll setup` |
|
|
68
68
|
| `roll init` | New project: create `AGENTS.md` + `BACKLOG.md` + `docs/features/` |
|
|
69
69
|
| `roll hook install` | Optional: global git hook that tags commits with the active AI client |
|
|
70
70
|
| `roll status` | Show sync state, skill links, and detected AI tools |
|
|
@@ -80,8 +80,8 @@ roll setup
|
|
|
80
80
|
cd my-app
|
|
81
81
|
roll init
|
|
82
82
|
|
|
83
|
-
# 3.
|
|
84
|
-
roll
|
|
83
|
+
# 3. Upgrade to a new release
|
|
84
|
+
roll update
|
|
85
85
|
|
|
86
86
|
# 4. Optional: tag commits with AI client name
|
|
87
87
|
roll hook install
|
package/bin/roll
CHANGED
|
@@ -4,7 +4,7 @@ set -euo pipefail
|
|
|
4
4
|
# Roll — AI Agent Convention Manager
|
|
5
5
|
# Single source of truth for how all AI coding agents behave.
|
|
6
6
|
|
|
7
|
-
VERSION="2026.505.
|
|
7
|
+
VERSION="2026.505.3"
|
|
8
8
|
ROLL_HOME="${ROLL_HOME:-${HOME}/.roll}"
|
|
9
9
|
ROLL_CONFIG="${ROLL_HOME}/config.yaml"
|
|
10
10
|
ROLL_GLOBAL="${ROLL_HOME}/conventions/global"
|
|
@@ -177,18 +177,18 @@ safe_copy() {
|
|
|
177
177
|
fi
|
|
178
178
|
echo ""
|
|
179
179
|
warn "File exists and differs: ${dst/#$HOME/~} 文件已存在且内容不同: ${dst/#$HOME/~}"
|
|
180
|
-
echo -e " ${BOLD}Overwrite?${NC} [
|
|
180
|
+
echo -e " ${BOLD}Overwrite?${NC} [Y/n/d(iff)] "
|
|
181
181
|
read -r answer
|
|
182
182
|
case "$answer" in
|
|
183
183
|
d|D|diff)
|
|
184
184
|
diff --color=auto "$dst" "$src" || true
|
|
185
185
|
echo ""
|
|
186
|
-
echo -e " ${BOLD}Overwrite?${NC} [
|
|
186
|
+
echo -e " ${BOLD}Overwrite?${NC} [Y/n] "
|
|
187
187
|
read -r answer2
|
|
188
|
-
[[ "$answer2" =~ ^[
|
|
188
|
+
[[ "$answer2" =~ ^[Nn]$ ]] && { info "Skipped: ${dst/#$HOME/\~} 已跳过: ${dst/#$HOME/\~}"; return; }
|
|
189
189
|
;;
|
|
190
|
-
|
|
191
|
-
*)
|
|
190
|
+
n|N) info "Skipped: ${dst/#$HOME/~} 已跳过: ${dst/#$HOME/~}"; return ;;
|
|
191
|
+
*) ;; # empty answer or 'y' / 'Y' → overwrite (default Yes)
|
|
192
192
|
esac
|
|
193
193
|
fi
|
|
194
194
|
|
|
@@ -541,6 +541,27 @@ cmd_setup() {
|
|
|
541
541
|
info "Next: run ${BOLD}roll init${NC} inside a project to initialize it. 下一步:在项目目录运行 roll init"
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
545
|
+
# COMMAND: update
|
|
546
|
+
# Thin wrapper: upgrade the npm-installed package, then re-sync via setup.
|
|
547
|
+
# Equivalent to: npm install -g @seanyao/roll@latest && roll setup
|
|
548
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
549
|
+
cmd_update() {
|
|
550
|
+
info "Current version: roll v${VERSION} 当前版本: roll v${VERSION}"
|
|
551
|
+
info "Upgrading via npm... 正在通过 npm 升级..."
|
|
552
|
+
echo ""
|
|
553
|
+
|
|
554
|
+
if ! npm install -g @seanyao/roll@latest; then
|
|
555
|
+
err "npm install failed. Check network/proxy and try again. npm 安装失败,请检查网络/代理后重试。"
|
|
556
|
+
exit 1
|
|
557
|
+
fi
|
|
558
|
+
|
|
559
|
+
echo ""
|
|
560
|
+
info "Re-syncing to AI tools... 正在重新同步到 AI 工具..."
|
|
561
|
+
echo ""
|
|
562
|
+
cmd_setup
|
|
563
|
+
}
|
|
564
|
+
|
|
544
565
|
# ─── Helper: merge global AGENTS.md into project (no type prompt) ────────────
|
|
545
566
|
# Fresh project: copies global AGENTS.md.
|
|
546
567
|
# Existing AGENTS.md: appends any ## sections missing from global.
|
|
@@ -551,25 +572,49 @@ _merge_global_to_project() {
|
|
|
551
572
|
|
|
552
573
|
[[ -f "$src" ]] || { warn "Global AGENTS.md not found at ${src/#$HOME/~}"; return; }
|
|
553
574
|
|
|
575
|
+
# Detect project type — controls which sections are included
|
|
576
|
+
local project_type skip_frontend=false
|
|
577
|
+
project_type="$(scan_project_type_from_files "$project_dir")"
|
|
578
|
+
case "$project_type" in
|
|
579
|
+
cli|backend-service|unknown) skip_frontend=true ;;
|
|
580
|
+
esac
|
|
581
|
+
|
|
554
582
|
if [[ ! -f "$dst" ]]; then
|
|
555
|
-
|
|
583
|
+
# Fresh create: write sections filtered by project type
|
|
584
|
+
local fc_h="" fc_b="" fc_pre=true fc_want=true
|
|
585
|
+
while IFS= read -r fc_line; do
|
|
586
|
+
if [[ "$fc_line" =~ ^##\ ]]; then
|
|
587
|
+
if [[ -n "$fc_h" && "$fc_want" == "true" ]]; then
|
|
588
|
+
printf '%s\n%s' "$fc_h" "$fc_b" >> "$dst"
|
|
589
|
+
fi
|
|
590
|
+
fc_h="$fc_line"; fc_b=""; fc_pre=false
|
|
591
|
+
fc_want=true
|
|
592
|
+
[[ "$skip_frontend" == "true" && "$fc_h" == "## 7. Frontend Default Stack" ]] && fc_want=false
|
|
593
|
+
elif [[ "$fc_pre" == "true" ]]; then
|
|
594
|
+
printf '%s\n' "$fc_line" >> "$dst"
|
|
595
|
+
else
|
|
596
|
+
fc_b+="$fc_line"$'\n'
|
|
597
|
+
fi
|
|
598
|
+
done < "$src"
|
|
599
|
+
if [[ -n "$fc_h" && "$fc_want" == "true" ]]; then
|
|
600
|
+
printf '%s\n%s' "$fc_h" "$fc_b" >> "$dst"
|
|
601
|
+
fi
|
|
556
602
|
ok "Created: AGENTS.md"
|
|
557
603
|
_ROLL_MERGE_SUMMARY+=("created|AGENTS.md")
|
|
558
604
|
return
|
|
559
605
|
fi
|
|
560
606
|
|
|
561
|
-
if diff -q "$src" "$dst" &>/dev/null; then
|
|
562
|
-
_ROLL_MERGE_SUMMARY+=("unchanged|AGENTS.md")
|
|
563
|
-
return
|
|
564
|
-
fi
|
|
565
|
-
|
|
566
607
|
# Section-merge: append any ## sections from global missing in project
|
|
567
608
|
local added=0 cur_h="" cur_b=""
|
|
568
609
|
while IFS= read -r line; do
|
|
569
610
|
if [[ "$line" =~ ^##\ ]]; then
|
|
570
611
|
if [[ -n "$cur_h" ]] && ! grep -qF "$cur_h" "$dst" 2>/dev/null; then
|
|
571
|
-
|
|
572
|
-
|
|
612
|
+
local skip_sec=false
|
|
613
|
+
[[ "$skip_frontend" == "true" && "$cur_h" == "## 7. Frontend Default Stack" ]] && skip_sec=true
|
|
614
|
+
if [[ "$skip_sec" == "false" ]]; then
|
|
615
|
+
printf '\n%s\n%s' "$cur_h" "$cur_b" >> "$dst"
|
|
616
|
+
added=$((added + 1))
|
|
617
|
+
fi
|
|
573
618
|
fi
|
|
574
619
|
cur_h="$line"; cur_b=""
|
|
575
620
|
elif [[ -n "$cur_h" ]]; then
|
|
@@ -577,8 +622,12 @@ _merge_global_to_project() {
|
|
|
577
622
|
fi
|
|
578
623
|
done < "$src"
|
|
579
624
|
if [[ -n "$cur_h" ]] && ! grep -qF "$cur_h" "$dst" 2>/dev/null; then
|
|
580
|
-
|
|
581
|
-
|
|
625
|
+
local skip_sec=false
|
|
626
|
+
[[ "$skip_frontend" == "true" && "$cur_h" == "## 7. Frontend Default Stack" ]] && skip_sec=true
|
|
627
|
+
if [[ "$skip_sec" == "false" ]]; then
|
|
628
|
+
printf '\n%s\n%s' "$cur_h" "$cur_b" >> "$dst"
|
|
629
|
+
added=$((added + 1))
|
|
630
|
+
fi
|
|
582
631
|
fi
|
|
583
632
|
|
|
584
633
|
if [[ $added -gt 0 ]]; then
|
|
@@ -589,6 +638,52 @@ _merge_global_to_project() {
|
|
|
589
638
|
fi
|
|
590
639
|
}
|
|
591
640
|
|
|
641
|
+
_merge_claude_to_project() {
|
|
642
|
+
local project_dir="$1"
|
|
643
|
+
local project_type
|
|
644
|
+
project_type="$(scan_project_type_from_files "$project_dir")"
|
|
645
|
+
|
|
646
|
+
local tpl_file="$ROLL_TEMPLATES/$project_type/CLAUDE.md"
|
|
647
|
+
[[ -f "$tpl_file" ]] || return 0 # No template for this project type
|
|
648
|
+
|
|
649
|
+
local claude_dir="$project_dir/.claude"
|
|
650
|
+
local out_file="$claude_dir/CLAUDE.md"
|
|
651
|
+
|
|
652
|
+
mkdir -p "$claude_dir"
|
|
653
|
+
|
|
654
|
+
if [[ ! -f "$out_file" ]]; then
|
|
655
|
+
cp "$tpl_file" "$out_file"
|
|
656
|
+
ok "Created: .claude/CLAUDE.md"
|
|
657
|
+
_ROLL_MERGE_SUMMARY+=("created|.claude/CLAUDE.md")
|
|
658
|
+
return
|
|
659
|
+
fi
|
|
660
|
+
|
|
661
|
+
# Append any ## sections from template missing in project file
|
|
662
|
+
local added=0 cur_h="" cur_b=""
|
|
663
|
+
while IFS= read -r line; do
|
|
664
|
+
if [[ "$line" =~ ^##\ ]]; then
|
|
665
|
+
if [[ -n "$cur_h" ]] && ! grep -qF "$cur_h" "$out_file" 2>/dev/null; then
|
|
666
|
+
printf '\n%s\n%s' "$cur_h" "$cur_b" >> "$out_file"
|
|
667
|
+
added=$((added + 1))
|
|
668
|
+
fi
|
|
669
|
+
cur_h="$line"; cur_b=""
|
|
670
|
+
elif [[ -n "$cur_h" ]]; then
|
|
671
|
+
cur_b+="$line"$'\n'
|
|
672
|
+
fi
|
|
673
|
+
done < "$tpl_file"
|
|
674
|
+
if [[ -n "$cur_h" ]] && ! grep -qF "$cur_h" "$out_file" 2>/dev/null; then
|
|
675
|
+
printf '\n%s\n%s' "$cur_h" "$cur_b" >> "$out_file"
|
|
676
|
+
added=$((added + 1))
|
|
677
|
+
fi
|
|
678
|
+
|
|
679
|
+
if [[ $added -gt 0 ]]; then
|
|
680
|
+
ok "Merged: .claude/CLAUDE.md ($added new sections)"
|
|
681
|
+
_ROLL_MERGE_SUMMARY+=("merged|.claude/CLAUDE.md")
|
|
682
|
+
else
|
|
683
|
+
_ROLL_MERGE_SUMMARY+=("unchanged|.claude/CLAUDE.md")
|
|
684
|
+
fi
|
|
685
|
+
}
|
|
686
|
+
|
|
592
687
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
593
688
|
# COMMAND: init
|
|
594
689
|
# Initialize or re-merge a project. Always operates on the current directory.
|
|
@@ -612,6 +707,7 @@ cmd_init() {
|
|
|
612
707
|
fi
|
|
613
708
|
|
|
614
709
|
_merge_global_to_project "$project_dir"
|
|
710
|
+
_merge_claude_to_project "$project_dir"
|
|
615
711
|
_write_backlog "$project_dir/BACKLOG.md"
|
|
616
712
|
_ensure_features_dir "$project_dir/docs/features"
|
|
617
713
|
print_merge_summary
|
|
@@ -1179,12 +1275,14 @@ usage() {
|
|
|
1179
1275
|
echo ""
|
|
1180
1276
|
echo "Commands:"
|
|
1181
1277
|
echo " setup [-f] [Machine] First-time install or re-sync 首次安装或重新同步"
|
|
1278
|
+
echo " update [Upgrade] npm install latest + re-sync 一键升级到最新版"
|
|
1182
1279
|
echo " init [Project] Create AGENTS.md + BACKLOG.md + docs/ 初始化项目工作流文件"
|
|
1183
1280
|
echo " hook [install|remove] [Optional] Manage global git hook 管理全局 git hook"
|
|
1184
1281
|
echo " status [Diagnostic] Show current state 显示当前状态"
|
|
1185
1282
|
echo ""
|
|
1186
1283
|
echo "Examples / 示例:"
|
|
1187
|
-
echo " roll setup # New machine
|
|
1284
|
+
echo " roll setup # New machine: first-time install 新机器首次安装"
|
|
1285
|
+
echo " roll update # Upgrade to latest version + re-sync 升级到最新版并重新同步"
|
|
1188
1286
|
echo " roll init # New or re-merge project (run in project) 新建或重新合并(项目目录)"
|
|
1189
1287
|
echo " roll hook install # Optional: tag commits with AI client 可选:提交时标记 AI 工具"
|
|
1190
1288
|
}
|
|
@@ -1195,6 +1293,7 @@ main() {
|
|
|
1195
1293
|
|
|
1196
1294
|
case "$cmd" in
|
|
1197
1295
|
setup) cmd_setup "$@" ;;
|
|
1296
|
+
update) cmd_update "$@" ;;
|
|
1198
1297
|
init) cmd_init "$@" ;;
|
|
1199
1298
|
hook) cmd_hook "$@" ;;
|
|
1200
1299
|
status) cmd_status "$@" ;;
|
|
@@ -1233,7 +1332,7 @@ _notify_update() {
|
|
|
1233
1332
|
local latest; latest=$(awk '{print $2}' "$cache" 2>/dev/null || true)
|
|
1234
1333
|
[[ -z "$latest" || "$latest" == "$VERSION" ]] && return
|
|
1235
1334
|
echo ""
|
|
1236
|
-
warn "v${latest} available — run '
|
|
1335
|
+
warn "v${latest} available — run 'roll update' to upgrade 有新版本 v${latest} — 运行 'roll update' 升级"
|
|
1237
1336
|
}
|
|
1238
1337
|
|
|
1239
1338
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
## Stack
|
|
6
6
|
|
|
7
|
-
- Node.js / TypeScript
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
- Distribution: npm package with bin entry
|
|
7
|
+
- Runtime / Language: {e.g. Node.js / TypeScript, Go, Python, Bash}
|
|
8
|
+
- Test framework: {e.g. Vitest, pytest, bats}
|
|
9
|
+
- Distribution: {e.g. npm, Homebrew, binary release}
|
|
11
10
|
|
|
12
11
|
## Claude Code Notes
|
|
13
12
|
|
|
@@ -15,4 +14,3 @@
|
|
|
15
14
|
- Test commands by running them in Bash, not just unit tests.
|
|
16
15
|
- Use `$roll-design` to plan command structure and options before implementation.
|
|
17
16
|
- Verify `--help` output is clear and complete for each command.
|
|
18
|
-
- Run `npm run build && node dist/index.js --help` before pushing.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanyao/roll",
|
|
3
|
-
"version": "2026.505.
|
|
3
|
+
"version": "2026.505.3",
|
|
4
4
|
"description": "Roll — Roll out features with AI agents",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "find tests/unit tests/integration -name '*.bats' | sort | xargs ./tests/helpers/bats-core/bin/bats"
|