@seanyao/roll 2026.510.9 → 2026.511.1
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/CHANGELOG.md +13 -0
- package/README.md +2 -2
- package/bin/roll +449 -18
- package/conventions/global/AGENTS.md +1 -1
- package/package.json +1 -1
- package/skills/roll-.changelog/SKILL.md +14 -3
- package/skills/roll-.clarify/SKILL.md +1 -1
- package/skills/roll-.qa/SKILL.md +2 -2
- package/skills/roll-brief/SKILL.md +24 -25
- package/skills/roll-build/SKILL.md +2 -2
- package/skills/roll-design/SKILL.md +1 -1
- package/skills/{roll-jot → roll-idea}/SKILL.md +6 -6
- package/skills/roll-loop/SKILL.md +7 -3
- package/skills/roll-notes/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2026.511.1
|
|
4
|
+
- **Changed**: roll loop 调度器切换到 launchd(macOS)— `roll setup` 自动安装 loop/dream/brief 三个 launchd 服务(默认关闭),`roll loop on/off/status` 统一走 launchctl 管理,幂等安装,Linux 保留 crontab 回退路径
|
|
5
|
+
- **Added**: roll-loop TCR 硬校验 — 故事完成后自动统计 `tcr:` 微提交数量,为 0 时将故事状态回退为 📋 Todo 并写 ALERT,防止 agent 跳过 TCR 节奏
|
|
6
|
+
- **Fixed**: CI 测试环境兼容 — 移除依赖本地 state.yaml 的 hello_world.bats,修复 GitHub Actions 持续失败
|
|
7
|
+
|
|
8
|
+
## v2026.510.10
|
|
9
|
+
- **Fixed**: release.sh changelog 同步时序修复 — 修正条件逻辑和执行顺序,确保每次发版时 changelog 正确更新
|
|
10
|
+
- **Added**: roll-loop 22:00 自动执行验证 — 新增 hello_world.bats 作为 loop 定时执行的端到端存档,可回放确认调度器正常工作
|
|
11
|
+
|
|
12
|
+
## v2026.510.9
|
|
13
|
+
- **Fixed**: CHANGELOG 改版本号分组 — 每个 release 独立 section,GitHub Release 增量内容提取正确
|
|
14
|
+
- **Fixed**: release.yml 加 fetch-depth: 0,确保历史 tag 在 workflow 中可见
|
|
15
|
+
|
|
3
16
|
## v2026.510.8
|
|
4
17
|
- **Fixed**: release.sh 自洽 — 内联 agent 检测和 changelog 同步,发版流程不依赖外部调用
|
|
5
18
|
- **Fixed**: roll release 命令重构 — 改为独立调用 roll-release skill,与 scripts/release.sh 解耦
|
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ Research → Design → Build → Check → Fix → (loop)
|
|
|
134
134
|
| Execute a planned Story | `$roll-build US-001` |
|
|
135
135
|
| Free-form feature request | `$roll-build "add search to admin"` |
|
|
136
136
|
| Bug fix | `$roll-fix FIX-001` |
|
|
137
|
-
| Fast backlog capture (bug / idea) | `$roll-
|
|
137
|
+
| Fast backlog capture (bug / idea) | `$roll-idea "description"` |
|
|
138
138
|
| High-risk logic (payments, auth, state machines) | `$roll-spar "feature"` |
|
|
139
139
|
| Deep research (product / company / tech) | `$roll-research "subject"` |
|
|
140
140
|
| Patrol production for regressions | `$roll-sentinel patrol` |
|
|
@@ -148,7 +148,7 @@ Research → Design → Build → Check → Fix → (loop)
|
|
|
148
148
|
| `$roll-build` | DESIGN+BUILD | Universal entry: Story ID, fix ID, or free-text fly mode |
|
|
149
149
|
| `$roll-design` | DESIGN | Multi-turn discuss → [peer review] → DDD model → solution design → [peer review] → write Stories to BACKLOG |
|
|
150
150
|
| `$roll-fix` | FIX | Bug fix / hotfix from BACKLOG |
|
|
151
|
-
| `$roll-
|
|
151
|
+
| `$roll-idea` | Support | Fast capture a bug or idea into BACKLOG.md |
|
|
152
152
|
| `$roll-spar` | BUILD | Adversarial TDD — Attacker writes tests, Defender writes code |
|
|
153
153
|
| `$roll-sentinel` | CHECK | Scheduled production patrol |
|
|
154
154
|
| `$roll-debug` | CHECK | Deep page diagnostics + root cause analysis |
|
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.
|
|
7
|
+
VERSION="2026.511.1"
|
|
8
8
|
ROLL_HOME="${ROLL_HOME:-${HOME}/.roll}"
|
|
9
9
|
ROLL_CONFIG="${ROLL_HOME}/config.yaml"
|
|
10
10
|
ROLL_GLOBAL="${ROLL_HOME}/conventions/global"
|
|
@@ -544,6 +544,12 @@ cmd_setup() {
|
|
|
544
544
|
_peer_ensure_state_dir
|
|
545
545
|
ok "Peer state directory ready. Peer 状态目录已就绪。"
|
|
546
546
|
|
|
547
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
548
|
+
echo ""
|
|
549
|
+
info "Installing launchd plists... 正在安装 LaunchAgents..."
|
|
550
|
+
_install_launchd_plists "$(pwd -P)"
|
|
551
|
+
fi
|
|
552
|
+
|
|
547
553
|
echo ""
|
|
548
554
|
ok "Setup complete. 初始化完成。"
|
|
549
555
|
|
|
@@ -1729,8 +1735,128 @@ cmd_agent() {
|
|
|
1729
1735
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
1730
1736
|
|
|
1731
1737
|
_LOOP_TAG="# roll-loop"
|
|
1738
|
+
_SHARED_ROOT="${HOME}/.shared/roll"
|
|
1732
1739
|
_LOOP_STATE="${HOME}/.shared/roll/loop/state.yaml"
|
|
1733
1740
|
_LOOP_ALERT="${HOME}/.shared/roll/loop/ALERT.md"
|
|
1741
|
+
_LAUNCHD_DIR="${HOME}/Library/LaunchAgents"
|
|
1742
|
+
|
|
1743
|
+
# Returns a filesystem-safe slug combining the project basename and a 6-char
|
|
1744
|
+
# hash of the full path, ensuring uniqueness across sibling dirs with same name.
|
|
1745
|
+
_project_slug() {
|
|
1746
|
+
local path="$1"
|
|
1747
|
+
local base; base=$(basename "$path")
|
|
1748
|
+
local hash
|
|
1749
|
+
if command -v md5 &>/dev/null; then
|
|
1750
|
+
hash=$(printf '%s' "$path" | md5 | cut -c1-6)
|
|
1751
|
+
else
|
|
1752
|
+
hash=$(printf '%s' "$path" | md5sum | cut -c1-6)
|
|
1753
|
+
fi
|
|
1754
|
+
base=$(printf '%s' "$base" | tr -cs '[:alnum:]' '-' | sed 's/-*$//')
|
|
1755
|
+
printf '%s' "${base}-${hash}"
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
_launchd_label() {
|
|
1759
|
+
local service="$1" project_path="$2"
|
|
1760
|
+
printf 'com.roll.%s.%s' "$service" "$(_project_slug "$project_path")"
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
_launchd_plist_path() {
|
|
1764
|
+
local service="$1" project_path="$2"
|
|
1765
|
+
printf '%s/%s.plist' "$_LAUNCHD_DIR" "$(_launchd_label "$service" "$project_path")"
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
_write_launchd_plist() {
|
|
1769
|
+
local plist_path="$1" label="$2" project_path="$3"
|
|
1770
|
+
local minute="$4" hour="$5" runner_script="$6"
|
|
1771
|
+
|
|
1772
|
+
local hour_xml=""
|
|
1773
|
+
[[ -n "$hour" ]] && hour_xml=" <key>Hour</key>
|
|
1774
|
+
<integer>${hour}</integer>
|
|
1775
|
+
"
|
|
1776
|
+
|
|
1777
|
+
local content
|
|
1778
|
+
content="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
|
1779
|
+
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
|
|
1780
|
+
<plist version=\"1.0\">
|
|
1781
|
+
<dict>
|
|
1782
|
+
<key>Label</key>
|
|
1783
|
+
<string>${label}</string>
|
|
1784
|
+
<key>ProgramArguments</key>
|
|
1785
|
+
<array>
|
|
1786
|
+
<string>/bin/bash</string>
|
|
1787
|
+
<string>-l</string>
|
|
1788
|
+
<string>${runner_script}</string>
|
|
1789
|
+
</array>
|
|
1790
|
+
<key>StartCalendarInterval</key>
|
|
1791
|
+
<dict>
|
|
1792
|
+
<key>Minute</key>
|
|
1793
|
+
<integer>${minute}</integer>
|
|
1794
|
+
${hour_xml} </dict>
|
|
1795
|
+
<key>WorkingDirectory</key>
|
|
1796
|
+
<string>${project_path}</string>
|
|
1797
|
+
</dict>
|
|
1798
|
+
</plist>"
|
|
1799
|
+
|
|
1800
|
+
if [[ -f "$plist_path" ]] && [[ "$(cat "$plist_path")" == "$content" ]]; then
|
|
1801
|
+
return 0
|
|
1802
|
+
fi
|
|
1803
|
+
printf '%s\n' "$content" > "$plist_path"
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
_write_runner_script() {
|
|
1807
|
+
local script_path="$1" project_path="$2" cmd="$3" log_path="$4"
|
|
1808
|
+
mkdir -p "$(dirname "$script_path")"
|
|
1809
|
+
printf '#!/bin/bash -l\ncd "%s" && %s >> "%s" 2>&1\n' "$project_path" "$cmd" "$log_path" > "$script_path"
|
|
1810
|
+
chmod +x "$script_path"
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
_launchd_is_loaded() {
|
|
1814
|
+
launchctl list "$1" &>/dev/null 2>&1
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
# Install launchd plist files (disabled by default) and runner scripts for
|
|
1818
|
+
# a given project path. Idempotent — skips unchanged files. Does NOT load.
|
|
1819
|
+
_install_launchd_plists() {
|
|
1820
|
+
local project_path="$1"
|
|
1821
|
+
local sd="${ROLL_HOME}/skills"
|
|
1822
|
+
local shared="${_SHARED_ROOT}"
|
|
1823
|
+
|
|
1824
|
+
mkdir -p "$_LAUNCHD_DIR"
|
|
1825
|
+
mkdir -p "${shared}/loop" "${shared}/dream" "${shared}/brief"
|
|
1826
|
+
|
|
1827
|
+
local services=("loop" "dream" "brief")
|
|
1828
|
+
local skill_names=("roll-loop" "roll-.dream" "roll-brief")
|
|
1829
|
+
local minutes=("0" "0" "0")
|
|
1830
|
+
local hours=("" "1" "8")
|
|
1831
|
+
|
|
1832
|
+
local updated=0
|
|
1833
|
+
for i in "${!services[@]}"; do
|
|
1834
|
+
local svc="${services[$i]}"
|
|
1835
|
+
local skill="${skill_names[$i]}"
|
|
1836
|
+
local minute="${minutes[$i]}"
|
|
1837
|
+
local hour="${hours[$i]}"
|
|
1838
|
+
local label; label=$(_launchd_label "$svc" "$project_path")
|
|
1839
|
+
local plist; plist=$(_launchd_plist_path "$svc" "$project_path")
|
|
1840
|
+
local runner="${shared}/${svc}/run.sh"
|
|
1841
|
+
local log="${shared}/${svc}/cron.log"
|
|
1842
|
+
local cmd; cmd=$(_agent_skill_cmd "${sd}/${skill}/SKILL.md" 2>/dev/null || echo "roll loop now")
|
|
1843
|
+
|
|
1844
|
+
_write_runner_script "$runner" "$project_path" "cd \"${project_path}\" && ${cmd}" "$log"
|
|
1845
|
+
|
|
1846
|
+
local before=""
|
|
1847
|
+
[[ -f "$plist" ]] && before=$(cat "$plist")
|
|
1848
|
+
_write_launchd_plist "$plist" "$label" "$project_path" "$minute" "$hour" "$runner"
|
|
1849
|
+
local after; after=$(cat "$plist")
|
|
1850
|
+
[[ "$before" != "$after" ]] && updated=$((updated + 1))
|
|
1851
|
+
done
|
|
1852
|
+
|
|
1853
|
+
if [[ $updated -gt 0 ]]; then
|
|
1854
|
+
ok "Launchd plists installed (${updated} updated) LaunchAgents 已安装"
|
|
1855
|
+
echo " Run: roll loop on to activate 运行 roll loop on 激活"
|
|
1856
|
+
else
|
|
1857
|
+
ok "Launchd plists up to date LaunchAgents 无需更新"
|
|
1858
|
+
fi
|
|
1859
|
+
}
|
|
1734
1860
|
|
|
1735
1861
|
_agent_skill_cmd() {
|
|
1736
1862
|
local skill_path="$1"
|
|
@@ -1738,7 +1864,7 @@ _agent_skill_cmd() {
|
|
|
1738
1864
|
# Strip YAML frontmatter inline for cron commands
|
|
1739
1865
|
local strip="awk 'NR==1 && /^---$/{skip=1;next} skip && /^---$/{skip=0;next} !skip{print}' '${skill_path}'"
|
|
1740
1866
|
case "$agent" in
|
|
1741
|
-
claude) echo "claude -p \"\$(${strip})\"" ;;
|
|
1867
|
+
claude) local _bin; _bin=$(command -v claude 2>/dev/null || echo "claude"); echo "${_bin} -p \"\$(${strip})\"" ;;
|
|
1742
1868
|
kimi) echo "kimi --quiet -p \"\$(${strip})\"" ;;
|
|
1743
1869
|
deepseek) echo "deepseek \"\$(${strip})\"" ;;
|
|
1744
1870
|
pi) echo "pi -p \"\$(${strip})\"" ;;
|
|
@@ -1751,31 +1877,57 @@ _agent_skill_cmd() {
|
|
|
1751
1877
|
cmd_loop() {
|
|
1752
1878
|
local subcmd="${1:-status}"; shift || true
|
|
1753
1879
|
case "$subcmd" in
|
|
1754
|
-
on)
|
|
1755
|
-
off)
|
|
1756
|
-
now)
|
|
1757
|
-
status)
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1880
|
+
on) _loop_on ;;
|
|
1881
|
+
off) _loop_off ;;
|
|
1882
|
+
now) _loop_now ;;
|
|
1883
|
+
status) _loop_status ;;
|
|
1884
|
+
monitor) _loop_monitor "${1:-3}" ;;
|
|
1885
|
+
resume) _loop_resume ;;
|
|
1886
|
+
reset) _loop_reset ;;
|
|
1887
|
+
*) err "Usage: roll loop <on|off|now|status|monitor|resume|reset>"; exit 1 ;;
|
|
1761
1888
|
esac
|
|
1762
1889
|
}
|
|
1763
1890
|
|
|
1764
1891
|
_loop_on() {
|
|
1765
1892
|
local project_path; project_path=$(pwd -P)
|
|
1766
1893
|
local agent; agent=$(_project_agent)
|
|
1767
|
-
local sd="${ROLL_HOME}/skills"
|
|
1768
1894
|
|
|
1895
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
1896
|
+
_install_launchd_plists "$project_path" >/dev/null
|
|
1897
|
+
|
|
1898
|
+
local all_loaded=true
|
|
1899
|
+
for svc in loop dream brief; do
|
|
1900
|
+
local label; label=$(_launchd_label "$svc" "$project_path")
|
|
1901
|
+
if ! _launchd_is_loaded "$label"; then
|
|
1902
|
+
all_loaded=false
|
|
1903
|
+
launchctl load "$(_launchd_plist_path "$svc" "$project_path")" 2>/dev/null || true
|
|
1904
|
+
fi
|
|
1905
|
+
done
|
|
1906
|
+
|
|
1907
|
+
if $all_loaded; then
|
|
1908
|
+
warn "Loop already enabled for this project 当前项目 loop 已启用"; return 0
|
|
1909
|
+
fi
|
|
1910
|
+
|
|
1911
|
+
ok "Loop enabled 已启用"
|
|
1912
|
+
echo " • roll-loop every hour :00 每小时整点"
|
|
1913
|
+
echo " • roll-.dream nightly at 01:00 每晚 01:00"
|
|
1914
|
+
echo " • roll-brief daily at 08:00 每天 08:00"
|
|
1915
|
+
echo " • Agent: ${agent} (change: roll agent use <name>)"
|
|
1916
|
+
return 0
|
|
1917
|
+
fi
|
|
1918
|
+
|
|
1919
|
+
# Linux: crontab
|
|
1920
|
+
local sd="${ROLL_HOME}/skills"
|
|
1769
1921
|
if crontab -l 2>/dev/null | grep -q "${_LOOP_TAG}:${project_path}"; then
|
|
1770
1922
|
warn "Loop already enabled for this project 当前项目 loop 已启用"; return 0
|
|
1771
1923
|
fi
|
|
1772
1924
|
|
|
1773
|
-
mkdir -p
|
|
1925
|
+
mkdir -p "${_SHARED_ROOT}/loop" "${_SHARED_ROOT}/dream" "${_SHARED_ROOT}/brief"
|
|
1774
1926
|
|
|
1775
1927
|
local loop_cmd dream_cmd brief_cmd
|
|
1776
|
-
loop_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-loop/SKILL.md") >>
|
|
1777
|
-
dream_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-.dream/SKILL.md") >>
|
|
1778
|
-
brief_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-brief/SKILL.md") >>
|
|
1928
|
+
loop_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-loop/SKILL.md") >> ${_SHARED_ROOT}/loop/cron.log 2>&1"
|
|
1929
|
+
dream_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-.dream/SKILL.md") >> ${_SHARED_ROOT}/dream/cron.log 2>&1"
|
|
1930
|
+
brief_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-brief/SKILL.md") >> ${_SHARED_ROOT}/brief/cron.log 2>&1"
|
|
1779
1931
|
|
|
1780
1932
|
(
|
|
1781
1933
|
crontab -l 2>/dev/null
|
|
@@ -1793,6 +1945,24 @@ _loop_on() {
|
|
|
1793
1945
|
|
|
1794
1946
|
_loop_off() {
|
|
1795
1947
|
local project_path; project_path=$(pwd -P)
|
|
1948
|
+
|
|
1949
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
1950
|
+
local any_loaded=false
|
|
1951
|
+
for svc in loop dream brief; do
|
|
1952
|
+
local label; label=$(_launchd_label "$svc" "$project_path")
|
|
1953
|
+
if _launchd_is_loaded "$label"; then
|
|
1954
|
+
any_loaded=true
|
|
1955
|
+
launchctl unload "$(_launchd_plist_path "$svc" "$project_path")" 2>/dev/null || true
|
|
1956
|
+
fi
|
|
1957
|
+
done
|
|
1958
|
+
if ! $any_loaded; then
|
|
1959
|
+
warn "Loop not enabled for this project 当前项目 loop 未启用"; return 0
|
|
1960
|
+
fi
|
|
1961
|
+
ok "Loop disabled 已停用"
|
|
1962
|
+
return 0
|
|
1963
|
+
fi
|
|
1964
|
+
|
|
1965
|
+
# Linux: crontab
|
|
1796
1966
|
if ! crontab -l 2>/dev/null | grep -q "${_LOOP_TAG}:${project_path}"; then
|
|
1797
1967
|
warn "Loop not enabled for this project 当前项目 loop 未启用"; return 0
|
|
1798
1968
|
fi
|
|
@@ -1805,14 +1975,22 @@ _loop_now() {
|
|
|
1805
1975
|
warn "Loop already running loop 正在运行中"; return 0
|
|
1806
1976
|
fi
|
|
1807
1977
|
info "Triggering loop cycle... 正在触发一个周期..."
|
|
1808
|
-
|
|
1978
|
+
local log_file="${_SHARED_ROOT}/loop/launchd.log"
|
|
1979
|
+
mkdir -p "$(dirname "$log_file")"
|
|
1980
|
+
_agent_run_skill "roll-loop" | tee -a "$log_file"
|
|
1809
1981
|
}
|
|
1810
1982
|
|
|
1811
1983
|
_loop_status() {
|
|
1812
1984
|
local project_path; project_path=$(pwd -P)
|
|
1813
1985
|
local agent; agent=$(_project_agent)
|
|
1814
1986
|
echo ""
|
|
1815
|
-
|
|
1987
|
+
local loop_enabled=false
|
|
1988
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
1989
|
+
_launchd_is_loaded "$(_launchd_label "loop" "$project_path")" && loop_enabled=true
|
|
1990
|
+
else
|
|
1991
|
+
crontab -l 2>/dev/null | grep -q "${_LOOP_TAG}:${project_path}" && loop_enabled=true
|
|
1992
|
+
fi
|
|
1993
|
+
if $loop_enabled; then
|
|
1816
1994
|
echo -e " Scheduler ${GREEN}● enabled${NC} Agent: ${CYAN}${agent}${NC}"
|
|
1817
1995
|
else
|
|
1818
1996
|
echo -e " Scheduler ${YELLOW}○ disabled${NC} run: roll loop on"
|
|
@@ -1842,6 +2020,176 @@ _loop_reset() {
|
|
|
1842
2020
|
fi
|
|
1843
2021
|
}
|
|
1844
2022
|
|
|
2023
|
+
# Count `tcr:` prefixed commits in the current git repo since started_at timestamp.
|
|
2024
|
+
_loop_tcr_count() {
|
|
2025
|
+
local started_at="$1"
|
|
2026
|
+
git log --oneline --since="${started_at}" 2>/dev/null \
|
|
2027
|
+
| awk '/^[a-f0-9]+ tcr:/{n++} END{print n+0}'
|
|
2028
|
+
}
|
|
2029
|
+
|
|
2030
|
+
# Verify TCR rhythm after a story completes. Returns 0 if ok, 1 if no TCR commits.
|
|
2031
|
+
# On failure: reverts story in BACKLOG.md to 📋 Todo and writes ALERT.
|
|
2032
|
+
_loop_enforce_tcr() {
|
|
2033
|
+
local story_id="$1"
|
|
2034
|
+
local started_at="${2:-}"
|
|
2035
|
+
|
|
2036
|
+
[[ -z "$started_at" ]] && return 0
|
|
2037
|
+
|
|
2038
|
+
local count; count=$(_loop_tcr_count "$started_at")
|
|
2039
|
+
|
|
2040
|
+
if [[ "$count" -eq 0 ]]; then
|
|
2041
|
+
# Revert story status
|
|
2042
|
+
if [[ -f "BACKLOG.md" ]]; then
|
|
2043
|
+
local tmp; tmp=$(mktemp)
|
|
2044
|
+
sed "/\[${story_id}\]/s/ | ✅ Done |/ | 📋 Todo |/" BACKLOG.md > "$tmp" \
|
|
2045
|
+
&& mv "$tmp" BACKLOG.md
|
|
2046
|
+
fi
|
|
2047
|
+
|
|
2048
|
+
# Write ALERT
|
|
2049
|
+
mkdir -p "$(dirname "$_LOOP_ALERT")"
|
|
2050
|
+
cat > "$_LOOP_ALERT" << EOF
|
|
2051
|
+
# ALERT — TCR check failed
|
|
2052
|
+
|
|
2053
|
+
**Time**: $(date '+%Y-%m-%d %H:%M')
|
|
2054
|
+
**Story**: ${story_id}
|
|
2055
|
+
**Reason**: zero tcr: commits since story start (${started_at})
|
|
2056
|
+
|
|
2057
|
+
**Action required** (choose one):
|
|
2058
|
+
- Add TCR commits and re-run: \`roll loop now\`
|
|
2059
|
+
- Take over manually: \`\$roll-build ${story_id}\`
|
|
2060
|
+
- Reset and retry: \`roll loop reset\` then \`roll loop now\`
|
|
2061
|
+
EOF
|
|
2062
|
+
return 1
|
|
2063
|
+
fi
|
|
2064
|
+
|
|
2065
|
+
return 0
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
_loop_monitor() {
|
|
2069
|
+
local interval="${1:-3}"
|
|
2070
|
+
local project_path; project_path=$(pwd -P)
|
|
2071
|
+
local project_name; project_name=$(basename "$project_path")
|
|
2072
|
+
|
|
2073
|
+
# Determine terminal clear capability
|
|
2074
|
+
local clear_cmd="clear"
|
|
2075
|
+
command -v clear &>/dev/null || clear_cmd="echo ''"
|
|
2076
|
+
|
|
2077
|
+
while true; do
|
|
2078
|
+
$clear_cmd
|
|
2079
|
+
local agent; agent=$(_project_agent)
|
|
2080
|
+
local now; now=$(date '+%Y-%m-%d %H:%M:%S')
|
|
2081
|
+
|
|
2082
|
+
echo -e "\n ${BOLD}${CYAN}roll loop monitor${NC} ${YELLOW}${project_name}${NC} ${now} (Ctrl-C to exit)\n"
|
|
2083
|
+
|
|
2084
|
+
# Services status (three services on macOS, single on Linux)
|
|
2085
|
+
echo -e " ${BOLD}Services 服务状态${NC} Agent: ${CYAN}${agent}${NC}"
|
|
2086
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
2087
|
+
local svc_info svc schedule
|
|
2088
|
+
for svc_info in "loop:hourly" "dream:01:00" "brief:08:00"; do
|
|
2089
|
+
svc="${svc_info%%:*}"
|
|
2090
|
+
schedule="${svc_info#*:}"
|
|
2091
|
+
if _launchd_is_loaded "$(_launchd_label "$svc" "$project_path")"; then
|
|
2092
|
+
printf " ${GREEN}%-8s ● enabled${NC} (%s)\n" "$svc" "$schedule"
|
|
2093
|
+
else
|
|
2094
|
+
printf " ${YELLOW}%-8s ○ disabled${NC} (%s)\n" "$svc" "$schedule"
|
|
2095
|
+
fi
|
|
2096
|
+
done
|
|
2097
|
+
else
|
|
2098
|
+
if crontab -l 2>/dev/null | grep -q "${_LOOP_TAG}:${project_path}"; then
|
|
2099
|
+
echo -e " ${GREEN}loop ● enabled${NC}"
|
|
2100
|
+
else
|
|
2101
|
+
echo -e " ${YELLOW}loop ○ disabled${NC} run: roll loop on"
|
|
2102
|
+
fi
|
|
2103
|
+
fi
|
|
2104
|
+
|
|
2105
|
+
# Current state
|
|
2106
|
+
if [[ -f "$_LOOP_STATE" ]]; then
|
|
2107
|
+
local status current_item started_at run_id
|
|
2108
|
+
status=$(grep '^status:' "$_LOOP_STATE" | awk '{print $2}')
|
|
2109
|
+
current_item=$(grep '^current_item:' "$_LOOP_STATE" | awk '{print $2}')
|
|
2110
|
+
started_at=$(grep '^started_at:' "$_LOOP_STATE" | cut -d' ' -f2- | tr -d '"')
|
|
2111
|
+
run_id=$(grep '^run_id:' "$_LOOP_STATE" | awk '{print $2}')
|
|
2112
|
+
echo ""
|
|
2113
|
+
case "$status" in
|
|
2114
|
+
running) echo -e " State ${GREEN}▶ running${NC} ${CYAN}${current_item}${NC} started: ${started_at} run: ${run_id}" ;;
|
|
2115
|
+
paused) echo -e " State ${RED}‖ paused${NC} on: ${current_item}" ;;
|
|
2116
|
+
idle) echo -e " State ${YELLOW}○ idle${NC}" ;;
|
|
2117
|
+
*) echo -e " State ${status}" ;;
|
|
2118
|
+
esac
|
|
2119
|
+
else
|
|
2120
|
+
echo ""
|
|
2121
|
+
echo -e " State ${YELLOW}○ no state file${NC}"
|
|
2122
|
+
fi
|
|
2123
|
+
|
|
2124
|
+
# Alert
|
|
2125
|
+
if [[ -f "$_LOOP_ALERT" ]]; then
|
|
2126
|
+
echo ""
|
|
2127
|
+
echo -e " ${RED}⚠ ALERT:${NC}"
|
|
2128
|
+
sed 's/^/ /' "$_LOOP_ALERT"
|
|
2129
|
+
fi
|
|
2130
|
+
|
|
2131
|
+
# Queue: pending items
|
|
2132
|
+
echo ""
|
|
2133
|
+
echo -e " ${BOLD}Queue 待处理队列${NC}"
|
|
2134
|
+
local backlog="BACKLOG.md"
|
|
2135
|
+
if [[ -f "$backlog" ]]; then
|
|
2136
|
+
local queue_count=0
|
|
2137
|
+
local fix_pending us_pending refactor_pending
|
|
2138
|
+
fix_pending=$(grep -E '^\| FIX-' "$backlog" | grep '📋 Todo' || true)
|
|
2139
|
+
us_pending=$(grep -E '^\| \[US-' "$backlog" | grep '📋 Todo' || true)
|
|
2140
|
+
refactor_pending=$(grep -E '^\| REFACTOR-' "$backlog" | grep '📋 Todo' || true)
|
|
2141
|
+
|
|
2142
|
+
# FIX first (priority)
|
|
2143
|
+
while IFS= read -r line; do
|
|
2144
|
+
[[ -z "$line" ]] && continue
|
|
2145
|
+
local id desc
|
|
2146
|
+
id=$(echo "$line" | awk -F'|' '{print $2}' | tr -d ' ')
|
|
2147
|
+
desc=$(echo "$line" | awk -F'|' '{print $3}' | sed 's/^ *//;s/ *$//' | cut -c1-60)
|
|
2148
|
+
printf " ${RED}%-14s${NC} %s\n" "$id" "$desc"
|
|
2149
|
+
(( queue_count++ )) || true
|
|
2150
|
+
done <<< "$fix_pending"
|
|
2151
|
+
|
|
2152
|
+
# US stories
|
|
2153
|
+
while IFS= read -r line; do
|
|
2154
|
+
[[ -z "$line" ]] && continue
|
|
2155
|
+
local id desc
|
|
2156
|
+
id=$(echo "$line" | sed 's/.*\[\(US-[^]]*\)\].*/\1/')
|
|
2157
|
+
desc=$(echo "$line" | awk -F'|' '{print $3}' | sed 's/^ *//;s/ *$//' | cut -c1-60)
|
|
2158
|
+
printf " ${CYAN}%-14s${NC} %s\n" "$id" "$desc"
|
|
2159
|
+
(( queue_count++ )) || true
|
|
2160
|
+
done <<< "$us_pending"
|
|
2161
|
+
|
|
2162
|
+
# Refactors
|
|
2163
|
+
while IFS= read -r line; do
|
|
2164
|
+
[[ -z "$line" ]] && continue
|
|
2165
|
+
local id desc
|
|
2166
|
+
id=$(echo "$line" | awk -F'|' '{print $2}' | tr -d ' ')
|
|
2167
|
+
desc=$(echo "$line" | awk -F'|' '{print $3}' | sed 's/^ *//;s/ *$//' | cut -c1-60)
|
|
2168
|
+
printf " ${YELLOW}%-14s${NC} %s\n" "$id" "$desc"
|
|
2169
|
+
(( queue_count++ )) || true
|
|
2170
|
+
done <<< "$refactor_pending"
|
|
2171
|
+
|
|
2172
|
+
[[ $queue_count -eq 0 ]] && echo -e " ${GREEN}✓ empty${NC}"
|
|
2173
|
+
else
|
|
2174
|
+
echo " BACKLOG.md not found"
|
|
2175
|
+
fi
|
|
2176
|
+
|
|
2177
|
+
# Log tail (launchd.log)
|
|
2178
|
+
local log_file="${_SHARED_ROOT}/loop/launchd.log"
|
|
2179
|
+
echo ""
|
|
2180
|
+
echo -e " ─────────────────────────────────────────────────────"
|
|
2181
|
+
echo -e " ${BOLD}Log Tail 实时日志${NC} (~/.shared/roll/loop/launchd.log, last 10 lines)"
|
|
2182
|
+
if [[ -f "$log_file" && -s "$log_file" ]]; then
|
|
2183
|
+
tail -10 "$log_file" | sed 's/^/ /'
|
|
2184
|
+
else
|
|
2185
|
+
echo -e " ${YELLOW}(no log yet)${NC}"
|
|
2186
|
+
fi
|
|
2187
|
+
|
|
2188
|
+
echo ""
|
|
2189
|
+
sleep "$interval"
|
|
2190
|
+
done
|
|
2191
|
+
}
|
|
2192
|
+
|
|
1845
2193
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
1846
2194
|
# BRIEF — owner-facing project digest
|
|
1847
2195
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -1872,6 +2220,75 @@ cmd_release() {
|
|
|
1872
2220
|
_agent_run_skill "roll-release"
|
|
1873
2221
|
}
|
|
1874
2222
|
|
|
2223
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
2224
|
+
# BACKLOG — show pending tasks
|
|
2225
|
+
# ═══════════════════════════════════════════════════════════════════════════════
|
|
2226
|
+
|
|
2227
|
+
cmd_backlog() {
|
|
2228
|
+
local backlog="BACKLOG.md"
|
|
2229
|
+
if [[ ! -f "$backlog" ]]; then
|
|
2230
|
+
err "BACKLOG.md not found — run 'roll init' first 未找到 BACKLOG.md,请先运行 roll init"
|
|
2231
|
+
return 1
|
|
2232
|
+
fi
|
|
2233
|
+
|
|
2234
|
+
local us_items fix_items refactor_items total=0
|
|
2235
|
+
|
|
2236
|
+
us_items=$(grep -E '^\| \[US-' "$backlog" | grep '📋 Todo' || true)
|
|
2237
|
+
fix_items=$(grep -E '^\| FIX-' "$backlog" | grep '📋 Todo' || true)
|
|
2238
|
+
refactor_items=$(grep -E '^\| REFACTOR-' "$backlog" | grep '📋 Todo' || true)
|
|
2239
|
+
|
|
2240
|
+
local us_count fix_count refactor_count
|
|
2241
|
+
us_count=$(echo "$us_items" | grep -c . || true)
|
|
2242
|
+
fix_count=$(echo "$fix_items" | grep -c . || true)
|
|
2243
|
+
refactor_count=$(echo "$refactor_items" | grep -c . || true)
|
|
2244
|
+
[[ -z "$us_items" ]] && us_count=0
|
|
2245
|
+
[[ -z "$fix_items" ]] && fix_count=0
|
|
2246
|
+
[[ -z "$refactor_items" ]] && refactor_count=0
|
|
2247
|
+
total=$(( us_count + fix_count + refactor_count ))
|
|
2248
|
+
|
|
2249
|
+
echo ""
|
|
2250
|
+
echo -e " ${BOLD}Pending Backlog 待处理任务${NC} (${total} items)"
|
|
2251
|
+
echo ""
|
|
2252
|
+
|
|
2253
|
+
if [[ $fix_count -gt 0 ]]; then
|
|
2254
|
+
echo -e " ${RED}Bug Fixes 缺陷修复 (${fix_count})${NC}"
|
|
2255
|
+
while IFS= read -r line; do
|
|
2256
|
+
local id desc
|
|
2257
|
+
id=$(echo "$line" | awk -F'|' '{print $2}' | tr -d ' ')
|
|
2258
|
+
desc=$(echo "$line" | awk -F'|' '{print $3}' | sed 's/^ *//;s/ *$//')
|
|
2259
|
+
printf " %-12s %s\n" "$id" "$desc"
|
|
2260
|
+
done <<< "$fix_items"
|
|
2261
|
+
echo ""
|
|
2262
|
+
fi
|
|
2263
|
+
|
|
2264
|
+
if [[ $us_count -gt 0 ]]; then
|
|
2265
|
+
echo -e " ${CYAN}User Stories 用户故事 (${us_count})${NC}"
|
|
2266
|
+
while IFS= read -r line; do
|
|
2267
|
+
local id desc
|
|
2268
|
+
id=$(echo "$line" | sed 's/.*\[\(US-[^]]*\)\].*/\1/')
|
|
2269
|
+
desc=$(echo "$line" | awk -F'|' '{print $3}' | sed 's/^ *//;s/ *$//')
|
|
2270
|
+
printf " %-14s %s\n" "$id" "$desc"
|
|
2271
|
+
done <<< "$us_items"
|
|
2272
|
+
echo ""
|
|
2273
|
+
fi
|
|
2274
|
+
|
|
2275
|
+
if [[ $refactor_count -gt 0 ]]; then
|
|
2276
|
+
echo -e " ${YELLOW}Refactors 重构 (${refactor_count})${NC}"
|
|
2277
|
+
while IFS= read -r line; do
|
|
2278
|
+
local id desc
|
|
2279
|
+
id=$(echo "$line" | awk -F'|' '{print $2}' | tr -d ' ')
|
|
2280
|
+
desc=$(echo "$line" | awk -F'|' '{print $3}' | sed 's/^ *//;s/ *$//')
|
|
2281
|
+
printf " %-16s %s\n" "$id" "$desc"
|
|
2282
|
+
done <<< "$refactor_items"
|
|
2283
|
+
echo ""
|
|
2284
|
+
fi
|
|
2285
|
+
|
|
2286
|
+
if [[ $total -eq 0 ]]; then
|
|
2287
|
+
echo -e " ${GREEN}✓ Nothing pending — backlog is clear 暂无待处理任务${NC}"
|
|
2288
|
+
echo ""
|
|
2289
|
+
fi
|
|
2290
|
+
}
|
|
2291
|
+
|
|
1875
2292
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
1876
2293
|
|
|
1877
2294
|
_dashboard() {
|
|
@@ -1888,6 +2305,17 @@ _dashboard() {
|
|
|
1888
2305
|
fi
|
|
1889
2306
|
[[ -f "$_LOOP_ALERT" ]] && echo -e " ${RED}⚠ ALERT — run: roll loop status${NC}"
|
|
1890
2307
|
|
|
2308
|
+
# Backlog summary
|
|
2309
|
+
if [[ -f "BACKLOG.md" ]]; then
|
|
2310
|
+
local pending_count
|
|
2311
|
+
pending_count=$(grep -c '📋 Todo' "BACKLOG.md" 2>/dev/null || echo 0)
|
|
2312
|
+
if (( pending_count > 0 )); then
|
|
2313
|
+
echo -e " Backlog ${YELLOW}${pending_count} pending${NC} run: roll backlog"
|
|
2314
|
+
else
|
|
2315
|
+
echo -e " Backlog ${GREEN}✓ clear${NC}"
|
|
2316
|
+
fi
|
|
2317
|
+
fi
|
|
2318
|
+
|
|
1891
2319
|
local briefs_dir="docs/briefs"
|
|
1892
2320
|
local latest; latest=$(ls "${briefs_dir}"/*.md 2>/dev/null | sort | tail -1 || true)
|
|
1893
2321
|
if [[ -n "$latest" ]]; then
|
|
@@ -1903,7 +2331,7 @@ _dashboard() {
|
|
|
1903
2331
|
fi
|
|
1904
2332
|
|
|
1905
2333
|
echo ""
|
|
1906
|
-
echo " loop <on|off|now|status|resume|reset> · brief · agent use <name> · release"
|
|
2334
|
+
echo " loop <on|off|now|status|monitor|resume|reset> · brief · backlog · agent use <name> · release"
|
|
1907
2335
|
echo " setup · update · init · status · peer · help"
|
|
1908
2336
|
echo ""
|
|
1909
2337
|
}
|
|
@@ -1930,8 +2358,9 @@ usage() {
|
|
|
1930
2358
|
echo " init [Project] Create AGENTS.md + BACKLOG.md + docs/ 初始化项目工作流文件"
|
|
1931
2359
|
echo " status [Diagnostic] Show current state 显示当前状态"
|
|
1932
2360
|
echo " peer [Peer Review] Cross-agent negotiation 跨 Agent 协商对审"
|
|
1933
|
-
echo " loop <on|off|now|status|resume|reset> [Autonomous] Manage scheduled BACKLOG executor 管理自主执行循环"
|
|
2361
|
+
echo " loop <on|off|now|status|monitor|resume|reset> [Autonomous] Manage scheduled BACKLOG executor 管理自主执行循环"
|
|
1934
2362
|
echo " brief [Digest] Show latest owner brief (regenerate if stale) 展示最新简报"
|
|
2363
|
+
echo " backlog [View] Show all pending tasks from BACKLOG.md 显示待处理任务清单"
|
|
1935
2364
|
echo " agent [use <name>|list] [Config] Per-project agent selection 切换项目 agent"
|
|
1936
2365
|
echo " release [Publish] Sync changelog + version bump + npm publish 同步日志并发版"
|
|
1937
2366
|
echo ""
|
|
@@ -1941,6 +2370,7 @@ usage() {
|
|
|
1941
2370
|
echo " roll init # New or re-merge project (run in project) 新建或重新合并(项目目录)"
|
|
1942
2371
|
echo " roll loop on # Enable autonomous loop (cron) 启用自主执行循环"
|
|
1943
2372
|
echo " roll brief # Show latest brief 查看最新简报"
|
|
2373
|
+
echo " roll backlog # Show pending BACKLOG items 查看待处理任务"
|
|
1944
2374
|
echo " roll agent use kimi # Switch this project to kimi 切换当前项目到 kimi"
|
|
1945
2375
|
|
|
1946
2376
|
}
|
|
@@ -1957,6 +2387,7 @@ main() {
|
|
|
1957
2387
|
peer) cmd_peer "$@" ;;
|
|
1958
2388
|
loop) cmd_loop "$@" ;;
|
|
1959
2389
|
brief) cmd_brief "$@" ;;
|
|
2390
|
+
backlog) cmd_backlog "$@" ;;
|
|
1960
2391
|
agent) cmd_agent "$@" ;;
|
|
1961
2392
|
release) cmd_release "$@" ;;
|
|
1962
2393
|
version|--version|-v) echo "roll v${VERSION}" ;;
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
## 4. Workflow
|
|
33
33
|
- **Scope Gate**: Only implement what is explicitly listed in the AC. Nothing more.
|
|
34
|
-
- Requests made in conversation are NOT AC — capture with `roll-
|
|
34
|
+
- Requests made in conversation are NOT AC — capture with `roll-idea` first.
|
|
35
35
|
- Any new Story/Fix requires design doc + user confirmation before TCR starts.
|
|
36
36
|
- Do not commit without user approval unless explicitly told to auto-commit.
|
|
37
37
|
- **TCR**: Test -> Green = Commit / Red = Revert. No WIP commits.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanyao/roll",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.511.1",
|
|
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"
|
|
@@ -76,12 +76,23 @@ Bad:
|
|
|
76
76
|
|
|
77
77
|
### 4. Version Number Format
|
|
78
78
|
|
|
79
|
+
Determine the current version being released:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
VERSION=$(node -e "process.stdout.write(require('./package.json').version)" 2>/dev/null \
|
|
83
|
+
|| git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//')
|
|
79
84
|
```
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
|
|
86
|
+
`package.json` is the authoritative source — it is updated before this skill runs. Fall back to git tags only if `package.json` is unavailable.
|
|
87
|
+
|
|
88
|
+
The CHANGELOG section header uses the full version string with a `v` prefix:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
## v${VERSION}
|
|
83
92
|
```
|
|
84
93
|
|
|
94
|
+
For the human-readable date display within entries, use `YYYY.MM.DD` format.
|
|
95
|
+
|
|
85
96
|
### 5. Generate CHANGELOG.md
|
|
86
97
|
|
|
87
98
|
**Create mode** (first time):
|
|
@@ -22,7 +22,7 @@ Auto-invoked by `roll-build` (Fly mode) when the user input is:
|
|
|
22
22
|
## When Not to Use
|
|
23
23
|
|
|
24
24
|
- Intent is already clear and actionable
|
|
25
|
-
- User gives a specific command with a skill trigger (e.g. `$roll-
|
|
25
|
+
- User gives a specific command with a skill trigger (e.g. `$roll-idea ...`)
|
|
26
26
|
- User is answering a clarification question you just asked
|
|
27
27
|
- The task is simple enough that misinterpretation risk is negligible
|
|
28
28
|
- User messy thoughts need restatement rather than questioning (use `$roll-.echo`)
|
package/skills/roll-.qa/SKILL.md
CHANGED
|
@@ -233,10 +233,10 @@ CI failure
|
|
|
233
233
|
|
|
234
234
|
```bash
|
|
235
235
|
# For fixable bugs — create FIX entry
|
|
236
|
-
$roll-
|
|
236
|
+
$roll-idea fix "CI: {step} fails — {root cause summary}"
|
|
237
237
|
|
|
238
238
|
# For flaky/environmental issues — create IDEA entry
|
|
239
|
-
$roll-
|
|
239
|
+
$roll-idea idea "CI: investigate flaky {test name}"
|
|
240
240
|
```
|
|
241
241
|
|
|
242
242
|
### Step 4: Execute Fix
|
|
@@ -95,52 +95,51 @@ A simple heuristic — not a gate, just a signal for the human:
|
|
|
95
95
|
|
|
96
96
|
### Step 4 — Write Brief
|
|
97
97
|
|
|
98
|
-
Output to `docs/briefs/YYYY-MM-DD-HH.md
|
|
98
|
+
Output to `docs/briefs/YYYY-MM-DD-HH.md`,全部用中文输出:
|
|
99
99
|
|
|
100
100
|
```markdown
|
|
101
|
-
#
|
|
101
|
+
# 简报 {YYYY-MM-DD HH:mm}
|
|
102
102
|
|
|
103
|
-
##
|
|
104
|
-
|
|
|
103
|
+
## 已完成
|
|
104
|
+
| 编号 | 描述 | 类型 |
|
|
105
105
|
|----|-------------|------|
|
|
106
|
-
| US-XXX | {
|
|
107
|
-
| FIX-XXX | {
|
|
108
|
-
| REFACTOR-XXX | {
|
|
106
|
+
| US-XXX | {标题} | 用户故事 |
|
|
107
|
+
| FIX-XXX | {标题} | 缺陷修复 |
|
|
108
|
+
| REFACTOR-XXX | {标题} | 重构 |
|
|
109
109
|
|
|
110
|
-
##
|
|
111
|
-
|
|
|
110
|
+
## 进行中
|
|
111
|
+
| 编号 | 描述 |
|
|
112
112
|
|----|-------------|
|
|
113
|
-
| US-XXX | {
|
|
113
|
+
| US-XXX | {标题} — 开始于 {date} |
|
|
114
114
|
|
|
115
|
-
##
|
|
116
|
-
|
|
|
115
|
+
## 待处理队列({N} 项)
|
|
116
|
+
| 编号 | 描述 | 优先级 |
|
|
117
117
|
|----|-------------|----------|
|
|
118
|
-
| US-XXX | {
|
|
118
|
+
| US-XXX | {标题} | 高 |
|
|
119
119
|
|
|
120
|
-
##
|
|
121
|
-
{
|
|
120
|
+
## 夜间巡检发现
|
|
121
|
+
{来自 docs/dream/ 的摘要,无则写"暂无新发现。"}
|
|
122
122
|
|
|
123
|
-
##
|
|
124
|
-
{
|
|
123
|
+
## 需要人工介入的升级事项
|
|
124
|
+
{任何告警,无则写"无 — agent 运行正常。"}
|
|
125
125
|
|
|
126
|
-
##
|
|
127
|
-
{✅
|
|
126
|
+
## 发布就绪状态
|
|
127
|
+
{✅ 可发布 / ⚠️ 暂缓 — 原因}
|
|
128
128
|
|
|
129
129
|
---
|
|
130
|
-
|
|
130
|
+
*下次定时简报:{datetime}*
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
### Step 5 — Notify
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
or CI log:
|
|
135
|
+
写完文件后在终端或 CI 日志中打印简报路径:
|
|
137
136
|
|
|
138
137
|
```
|
|
139
|
-
📋
|
|
140
|
-
|
|
138
|
+
📋 简报已生成:docs/briefs/2026-05-10-08.md
|
|
139
|
+
发布就绪:✅ 可发布
|
|
141
140
|
```
|
|
142
141
|
|
|
143
|
-
|
|
142
|
+
有升级事项时须显著打印,不得遗漏。
|
|
144
143
|
|
|
145
144
|
## Scheduler Configuration
|
|
146
145
|
|
|
@@ -18,7 +18,7 @@ One entry point. Any input. Full delivery.
|
|
|
18
18
|
Input received
|
|
19
19
|
├── matches "US-[A-Z]+-[0-9]+" → Story mode: read BACKLOG → TCR workflow
|
|
20
20
|
├── matches "FIX-[A-Z]+-[0-9]+" → redirect to $roll-fix
|
|
21
|
-
├── matches "IDEA-[0-9]+" → redirect to $roll-
|
|
21
|
+
├── matches "IDEA-[0-9]+" → redirect to $roll-idea (lookup and expand)
|
|
22
22
|
└── anything else → Fly mode: clarify → design → execute
|
|
23
23
|
```
|
|
24
24
|
|
|
@@ -654,7 +654,7 @@ When complex state management is error-prone → consider full reset + re-initia
|
|
|
654
654
|
roll-build → ship anything (new idea, US-ID, free-text request)
|
|
655
655
|
roll-fix → fix a specific known bug (FIX-XXX / BUG-XXX)
|
|
656
656
|
roll-design → plan and design before building (no code output)
|
|
657
|
-
roll-
|
|
657
|
+
roll-idea → fast capture a bug or idea into BACKLOG.md
|
|
658
658
|
roll-.clarify → passive scope clarification for vague build requests
|
|
659
659
|
```
|
|
660
660
|
|
|
@@ -29,7 +29,7 @@ Discuss approaches, design architecture, plan requirements, and write to `BACKLO
|
|
|
29
29
|
|
|
30
30
|
## When Not to Use
|
|
31
31
|
|
|
32
|
-
- One-liner capture of ideas or bugs (use `$roll-
|
|
32
|
+
- One-liner capture of ideas or bugs (use `$roll-idea`)
|
|
33
33
|
- Executing an already-split US-XXX (use `$roll-build`)
|
|
34
34
|
- Fixing a well-defined FIX-XXX (use `$roll-fix`)
|
|
35
35
|
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: roll-
|
|
2
|
+
name: roll-idea
|
|
3
3
|
license: MIT
|
|
4
4
|
allowed-tools: "Read, Edit"
|
|
5
5
|
description: "Fast backlog capture. Analyzes a short description, classifies it as bug or idea, and appends it to BACKLOG.md with an auto-incremented ID."
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# roll-
|
|
8
|
+
# roll-idea
|
|
9
9
|
|
|
10
10
|
> One-liner in, backlog entry out. No questions asked.
|
|
11
11
|
|
|
12
12
|
## Trigger
|
|
13
13
|
|
|
14
|
-
User explicitly invokes `roll-
|
|
14
|
+
User explicitly invokes `roll-idea` with a free-text description.
|
|
15
15
|
|
|
16
16
|
```
|
|
17
|
-
$roll-
|
|
18
|
-
$roll-
|
|
19
|
-
$roll-
|
|
17
|
+
$roll-idea 评价页面的星星也要纳入到 draft 的 scope 里
|
|
18
|
+
$roll-idea 手机端星星指标一行一个从上往下排
|
|
19
|
+
$roll-idea 给 HOD 加一个批量导出 PDF 的功能
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
## When Not to Use
|
|
@@ -92,9 +92,13 @@ run_id: loop-20260510-0200
|
|
|
92
92
|
|
|
93
93
|
After each item completes:
|
|
94
94
|
|
|
95
|
-
1.
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
1. **TCR 硬校验** — call `_loop_enforce_tcr <story_id> <started_at>`:
|
|
96
|
+
- Count `tcr:` prefix commits since `started_at` via `git log --oneline --since=<started_at>`
|
|
97
|
+
- Count == 0 → revert story status in BACKLOG.md from ✅ Done → 📋 Todo; write ALERT to `~/.shared/roll/loop/ALERT.md` with story ID, time, reason "zero tcr: commits since story start", and suggested actions (`roll loop now` / `$roll-build <id>` / `roll loop reset`)
|
|
98
|
+
- Count > 0 → continue normally
|
|
99
|
+
2. Update state file: `status: idle`
|
|
100
|
+
3. Check if a Feature is now fully complete (all its Stories ✅)
|
|
101
|
+
4. If yes and `brief_on_feature_complete: true` → invoke `Skill("roll-brief")`
|
|
98
102
|
|
|
99
103
|
### Step 5 — Write Run Summary
|
|
100
104
|
|
|
@@ -23,7 +23,7 @@ $roll-notes 今天的 code review 给了很好的反馈
|
|
|
23
23
|
|
|
24
24
|
## When Not to Use
|
|
25
25
|
|
|
26
|
-
- Capturing a bug or feature idea into BACKLOG (use `$roll-
|
|
26
|
+
- Capturing a bug or feature idea into BACKLOG (use `$roll-idea`)
|
|
27
27
|
- Generating user-facing release notes (use `$roll-.changelog`)
|
|
28
28
|
- Writing design documents or AC (use `$roll-design`)
|
|
29
29
|
|