@seanyao/roll 2026.424.3 → 2026.424.4
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/bin/roll +74 -4
- package/package.json +1 -1
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.424.
|
|
7
|
+
VERSION="2026.424.4"
|
|
8
8
|
ROLL_HOME="${ROLL_HOME:-${HOME}/.roll}"
|
|
9
9
|
ROLL_CONFIG="${ROLL_HOME}/config.yaml"
|
|
10
10
|
ROLL_GLOBAL="${ROLL_HOME}/conventions/global"
|
|
@@ -64,6 +64,24 @@ lower_name() {
|
|
|
64
64
|
echo "$1" | tr '[:upper:]' '[:lower:]'
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
# Check if an AI tool is actually installed.
|
|
68
|
+
# Most tools create their own config dir; Trae on macOS uses Library/Application Support
|
|
69
|
+
# and expects roll to manage ~/.trae/ — so we detect via the app directory instead.
|
|
70
|
+
_is_ai_installed() {
|
|
71
|
+
local ai_dir="$1"
|
|
72
|
+
[[ -d "$ai_dir" ]] && return 0
|
|
73
|
+
local bn
|
|
74
|
+
bn="$(basename "$ai_dir" | sed 's/^\.//')"
|
|
75
|
+
case "$bn" in
|
|
76
|
+
trae)
|
|
77
|
+
[[ -d "$HOME/Library/Application Support/Trae" ]] ||
|
|
78
|
+
[[ -d "$HOME/.config/Trae" ]]
|
|
79
|
+
return
|
|
80
|
+
;;
|
|
81
|
+
esac
|
|
82
|
+
return 1
|
|
83
|
+
}
|
|
84
|
+
|
|
67
85
|
# ─── Helper: read config value ───────────────────────────────────────────────
|
|
68
86
|
config_get() {
|
|
69
87
|
local key="$1"
|
|
@@ -87,6 +105,53 @@ _get_ai_tools() {
|
|
|
87
105
|
done
|
|
88
106
|
}
|
|
89
107
|
|
|
108
|
+
# Add any ai_* keys from the default set that are missing from the user's config.
|
|
109
|
+
# Non-destructive: never removes or modifies existing entries.
|
|
110
|
+
_ensure_config_entries() {
|
|
111
|
+
[[ -f "$ROLL_CONFIG" ]] || return
|
|
112
|
+
|
|
113
|
+
local -a default_keys=(
|
|
114
|
+
"ai_claude:~/.claude|CLAUDE.md|CLAUDE.md"
|
|
115
|
+
"ai_gemini:~/.gemini|GEMINI.md|GEMINI.md"
|
|
116
|
+
"ai_kimi:~/.kimi|AGENTS.md|AGENTS.md"
|
|
117
|
+
"ai_codex:~/.codex|AGENTS.md|AGENTS.md"
|
|
118
|
+
"ai_cursor:~/.cursor|.cursor-rules|.cursor-rules"
|
|
119
|
+
"ai_trae:~/.trae|user_rules.md|project_rules.md"
|
|
120
|
+
"ai_openclaw:~/.openclaw/workspace|AGENTS.md|AGENTS.md"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
local added=0
|
|
124
|
+
local tmp
|
|
125
|
+
tmp="$(mktemp)"
|
|
126
|
+
cp "$ROLL_CONFIG" "$tmp"
|
|
127
|
+
|
|
128
|
+
for entry in "${default_keys[@]}"; do
|
|
129
|
+
local key="${entry%%:*}"
|
|
130
|
+
local val="${entry#*:}"
|
|
131
|
+
if ! grep -qE "^${key}:" "$ROLL_CONFIG" 2>/dev/null; then
|
|
132
|
+
if grep -q "^# User preferences" "$tmp" 2>/dev/null; then
|
|
133
|
+
local new_tmp
|
|
134
|
+
new_tmp="$(mktemp)"
|
|
135
|
+
while IFS= read -r line; do
|
|
136
|
+
[[ "$line" == "# User preferences" ]] && echo "${key}: ${val}" >> "$new_tmp"
|
|
137
|
+
echo "$line" >> "$new_tmp"
|
|
138
|
+
done < "$tmp"
|
|
139
|
+
mv "$new_tmp" "$tmp"
|
|
140
|
+
else
|
|
141
|
+
echo "${key}: ${val}" >> "$tmp"
|
|
142
|
+
fi
|
|
143
|
+
added=$((added + 1))
|
|
144
|
+
warn "Added missing config entry: ${key} 已添加缺失配置项: ${key}"
|
|
145
|
+
fi
|
|
146
|
+
done
|
|
147
|
+
|
|
148
|
+
if [[ $added -gt 0 ]]; then
|
|
149
|
+
cp "$tmp" "$ROLL_CONFIG"
|
|
150
|
+
ok "Config updated with $added new entries 配置已更新,新增 $added 条目"
|
|
151
|
+
fi
|
|
152
|
+
rm -f "$tmp"
|
|
153
|
+
}
|
|
154
|
+
|
|
90
155
|
# Extract fields from a "<dir>|<config>|<src>" entry
|
|
91
156
|
_ai_dir() { echo "$1" | cut -d'|' -f1; }
|
|
92
157
|
_ai_config() { echo "$1" | cut -d'|' -f2; }
|
|
@@ -246,6 +311,9 @@ YAML
|
|
|
246
311
|
ok "Created: ~/.roll/config.yaml 已创建: ~/.roll/config.yaml"
|
|
247
312
|
fi
|
|
248
313
|
|
|
314
|
+
# Ensure all expected ai_* keys exist (handles upgrades where new tools were added)
|
|
315
|
+
_ensure_config_entries
|
|
316
|
+
|
|
249
317
|
}
|
|
250
318
|
|
|
251
319
|
# ─── Internal: create or repair per-skill symlinks (non-destructive) ─────────
|
|
@@ -258,7 +326,8 @@ _link_skills() {
|
|
|
258
326
|
while IFS= read -r entry; do
|
|
259
327
|
local ai_dir
|
|
260
328
|
ai_dir="$(_ai_dir "$entry")"
|
|
261
|
-
|
|
329
|
+
_is_ai_installed "$ai_dir" || continue
|
|
330
|
+
mkdir -p "$ai_dir"
|
|
262
331
|
|
|
263
332
|
local ai_name ai_dir_real skills_dir
|
|
264
333
|
ai_name="$(ai_tool_name "$ai_dir")"
|
|
@@ -355,8 +424,8 @@ _sync_convention_for_tool() {
|
|
|
355
424
|
local dst_dir
|
|
356
425
|
dst_dir="$(dirname "$main_dst")"
|
|
357
426
|
|
|
358
|
-
# Only proceed if
|
|
359
|
-
if [[ "$dst_dir" != "$HOME/.claude" ]] &&
|
|
427
|
+
# Only proceed if Claude (always) or the tool is installed
|
|
428
|
+
if [[ "$dst_dir" != "$HOME/.claude" ]] && ! _is_ai_installed "$dst_dir"; then
|
|
360
429
|
return
|
|
361
430
|
fi
|
|
362
431
|
mkdir -p "$dst_dir"
|
|
@@ -467,6 +536,7 @@ cmd_sync() {
|
|
|
467
536
|
info "Syncing from repo to AI tools... 正在从仓库同步到 AI 工具..."
|
|
468
537
|
echo ""
|
|
469
538
|
_pull_conventions "$force"
|
|
539
|
+
_ensure_config_entries
|
|
470
540
|
echo ""
|
|
471
541
|
_sync_conventions "$force"
|
|
472
542
|
echo ""
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanyao/roll",
|
|
3
|
-
"version": "2026.424.
|
|
3
|
+
"version": "2026.424.4",
|
|
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"
|