@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 CHANGED
@@ -48,8 +48,7 @@ roll setup
48
48
  To update:
49
49
 
50
50
  ```bash
51
- npm install -g @seanyao/roll@latest
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. Re-sync after editing ~/.roll/config.yaml or after upgrading
84
- roll setup
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.1"
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} [y/N/d(iff)] "
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} [y/N] "
186
+ echo -e " ${BOLD}Overwrite?${NC} [Y/n] "
187
187
  read -r answer2
188
- [[ "$answer2" =~ ^[Yy]$ ]] || { info "Skipped: ${dst/#$HOME/\~} 已跳过: ${dst/#$HOME/\~}"; return; }
188
+ [[ "$answer2" =~ ^[Nn]$ ]] && { info "Skipped: ${dst/#$HOME/\~} 已跳过: ${dst/#$HOME/\~}"; return; }
189
189
  ;;
190
- y|Y) ;;
191
- *) info "Skipped: ${dst/#$HOME/~} 已跳过: ${dst/#$HOME/~}"; return ;;
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
- cp "$src" "$dst"
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
- printf '\n%s\n%s' "$cur_h" "$cur_b" >> "$dst"
572
- added=$((added + 1))
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
- printf '\n%s\n%s' "$cur_h" "$cur_b" >> "$dst"
581
- added=$((added + 1))
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, or re-sync after npm update 新机器或更新后重新同步"
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 'npm install -g @seanyao/roll@latest && roll setup' to upgrade 有新版本 v${latest} — 运行 'npm install -g @seanyao/roll@latest && roll setup' 升级"
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
- - CLI framework: commander or citty
9
- - Testing: Vitest + execa (CLI integration tests)
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.1",
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"