@seanyao/roll 2026.510.5 → 2026.510.7
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
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.510.
|
|
7
|
+
VERSION="2026.510.7"
|
|
8
8
|
ROLL_HOME="${ROLL_HOME:-${HOME}/.roll}"
|
|
9
9
|
ROLL_CONFIG="${ROLL_HOME}/config.yaml"
|
|
10
10
|
ROLL_GLOBAL="${ROLL_HOME}/conventions/global"
|
|
@@ -1332,7 +1332,16 @@ _peer_call() {
|
|
|
1332
1332
|
output="$(kimi --quiet -p "$prompt" 2>"$stderr_log" || true)"
|
|
1333
1333
|
;;
|
|
1334
1334
|
pi)
|
|
1335
|
-
output="$(pi -p
|
|
1335
|
+
output="$(pi -p "$prompt" 2>"$stderr_log" || true)"
|
|
1336
|
+
;;
|
|
1337
|
+
deepseek)
|
|
1338
|
+
output="$(deepseek "$prompt" 2>"$stderr_log" || true)"
|
|
1339
|
+
;;
|
|
1340
|
+
codex)
|
|
1341
|
+
output="$(codex exec --json --output-last-message "$prompt" 2>"$stderr_log" || true)"
|
|
1342
|
+
;;
|
|
1343
|
+
opencode)
|
|
1344
|
+
output="$(opencode run "$prompt" 2>"$stderr_log" || true)"
|
|
1336
1345
|
;;
|
|
1337
1346
|
*)
|
|
1338
1347
|
err "Unsupported peer: $to 不支持的 peer: $to"
|
|
@@ -1653,16 +1662,25 @@ _project_agent() {
|
|
|
1653
1662
|
fi
|
|
1654
1663
|
}
|
|
1655
1664
|
|
|
1665
|
+
_skill_content() {
|
|
1666
|
+
# Strip YAML frontmatter (---...---) — it's roll-internal metadata, not agent instructions
|
|
1667
|
+
awk 'NR==1 && /^---$/{skip=1;next} skip && /^---$/{skip=0;next} !skip{print}' "$1"
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1656
1670
|
_agent_run_skill() {
|
|
1657
1671
|
local skill="$1"
|
|
1658
1672
|
local agent; agent=$(_project_agent)
|
|
1659
1673
|
local skill_file="${ROLL_HOME}/skills/${skill}/SKILL.md"
|
|
1660
1674
|
[[ -f "$skill_file" ]] || { err "Skill not found: ${skill}"; return 1; }
|
|
1675
|
+
local content; content=$(_skill_content "$skill_file")
|
|
1661
1676
|
case "$agent" in
|
|
1662
|
-
claude) claude -p "$
|
|
1663
|
-
kimi) kimi --quiet
|
|
1664
|
-
deepseek) deepseek "$
|
|
1665
|
-
|
|
1677
|
+
claude) claude -p "$content" ;;
|
|
1678
|
+
kimi) kimi --quiet -p "$content" ;;
|
|
1679
|
+
deepseek) deepseek "$content" ;;
|
|
1680
|
+
pi) pi -p "$content" ;;
|
|
1681
|
+
codex) codex exec "$content" ;;
|
|
1682
|
+
opencode) opencode run "$content" ;;
|
|
1683
|
+
*) err "Unknown agent '${agent}'. Run: roll agent use <claude|kimi|deepseek|pi|codex|opencode>"; return 1 ;;
|
|
1666
1684
|
esac
|
|
1667
1685
|
}
|
|
1668
1686
|
|
|
@@ -1671,10 +1689,10 @@ cmd_agent() {
|
|
|
1671
1689
|
case "$subcmd" in
|
|
1672
1690
|
use)
|
|
1673
1691
|
local name="${1:-}"
|
|
1674
|
-
[[ -z "$name" ]] && { err "Usage: roll agent use <claude|kimi|deepseek>"; exit 1; }
|
|
1692
|
+
[[ -z "$name" ]] && { err "Usage: roll agent use <claude|kimi|deepseek|pi|codex|opencode>"; exit 1; }
|
|
1675
1693
|
command -v "$name" &>/dev/null || warn "${name} not found in PATH — setting anyway 未找到,仍写入配置"
|
|
1676
1694
|
if [[ -f ".roll.yaml" ]] && grep -q "^agent:" .roll.yaml; then
|
|
1677
|
-
sed
|
|
1695
|
+
local tmp; tmp=$(mktemp) && sed "s/^agent:.*/agent: ${name}/" .roll.yaml > "$tmp" && mv "$tmp" .roll.yaml
|
|
1678
1696
|
else
|
|
1679
1697
|
echo "agent: ${name}" >> .roll.yaml
|
|
1680
1698
|
fi
|
|
@@ -1714,6 +1732,22 @@ _LOOP_TAG="# roll-loop"
|
|
|
1714
1732
|
_LOOP_STATE="${HOME}/.shared/roll/loop/state.yaml"
|
|
1715
1733
|
_LOOP_ALERT="${HOME}/.shared/roll/loop/ALERT.md"
|
|
1716
1734
|
|
|
1735
|
+
_agent_skill_cmd() {
|
|
1736
|
+
local skill_path="$1"
|
|
1737
|
+
local agent; agent=$(_project_agent)
|
|
1738
|
+
# Strip YAML frontmatter inline for cron commands
|
|
1739
|
+
local strip="awk 'NR==1 && /^---$/{skip=1;next} skip && /^---$/{skip=0;next} !skip{print}' '${skill_path}'"
|
|
1740
|
+
case "$agent" in
|
|
1741
|
+
claude) echo "claude -p \"\$(${strip})\"" ;;
|
|
1742
|
+
kimi) echo "kimi --quiet -p \"\$(${strip})\"" ;;
|
|
1743
|
+
deepseek) echo "deepseek \"\$(${strip})\"" ;;
|
|
1744
|
+
pi) echo "pi -p \"\$(${strip})\"" ;;
|
|
1745
|
+
codex) echo "codex exec \"\$(${strip})\"" ;;
|
|
1746
|
+
opencode) echo "opencode run \"\$(${strip})\"" ;;
|
|
1747
|
+
*) err "Unknown agent '${agent}'. Run: roll agent use <claude|kimi|deepseek|pi|codex|opencode>"; return 1 ;;
|
|
1748
|
+
esac
|
|
1749
|
+
}
|
|
1750
|
+
|
|
1717
1751
|
cmd_loop() {
|
|
1718
1752
|
local subcmd="${1:-status}"; shift || true
|
|
1719
1753
|
case "$subcmd" in
|
|
@@ -1721,7 +1755,9 @@ cmd_loop() {
|
|
|
1721
1755
|
off) _loop_off ;;
|
|
1722
1756
|
now) _loop_now ;;
|
|
1723
1757
|
status) _loop_status ;;
|
|
1724
|
-
|
|
1758
|
+
resume) _loop_resume ;;
|
|
1759
|
+
reset) _loop_reset ;;
|
|
1760
|
+
*) err "Usage: roll loop <on|off|now|status|resume|reset>"; exit 1 ;;
|
|
1725
1761
|
esac
|
|
1726
1762
|
}
|
|
1727
1763
|
|
|
@@ -1737,9 +1773,9 @@ _loop_on() {
|
|
|
1737
1773
|
mkdir -p ~/.shared/roll/{loop,dream,brief}
|
|
1738
1774
|
|
|
1739
1775
|
local loop_cmd dream_cmd brief_cmd
|
|
1740
|
-
loop_cmd="cd \"${project_path}\" && $
|
|
1741
|
-
dream_cmd="cd \"${project_path}\" && $
|
|
1742
|
-
brief_cmd="cd \"${project_path}\" && $
|
|
1776
|
+
loop_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-loop/SKILL.md") >> ~/.shared/roll/loop/cron.log 2>&1"
|
|
1777
|
+
dream_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-.dream/SKILL.md") >> ~/.shared/roll/dream/cron.log 2>&1"
|
|
1778
|
+
brief_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-brief/SKILL.md") >> ~/.shared/roll/brief/cron.log 2>&1"
|
|
1743
1779
|
|
|
1744
1780
|
(
|
|
1745
1781
|
crontab -l 2>/dev/null
|
|
@@ -1786,6 +1822,26 @@ _loop_status() {
|
|
|
1786
1822
|
echo ""
|
|
1787
1823
|
}
|
|
1788
1824
|
|
|
1825
|
+
_loop_resume() {
|
|
1826
|
+
if [[ ! -f "$_LOOP_STATE" ]]; then
|
|
1827
|
+
warn "No loop state found — nothing to resume 未找到 loop 状态,无需恢复"; return 0
|
|
1828
|
+
fi
|
|
1829
|
+
if grep -q "status: running" "$_LOOP_STATE" 2>/dev/null; then
|
|
1830
|
+
warn "Loop already running loop 正在运行中"; return 0
|
|
1831
|
+
fi
|
|
1832
|
+
info "Resuming loop from last state... 正在从上次状态恢复..."
|
|
1833
|
+
_agent_run_skill "roll-loop"
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
_loop_reset() {
|
|
1837
|
+
if [[ -f "$_LOOP_STATE" ]]; then
|
|
1838
|
+
rm -f "$_LOOP_STATE"
|
|
1839
|
+
ok "Loop state cleared — will start fresh on next run loop 状态已清除,下次运行将重新开始"
|
|
1840
|
+
else
|
|
1841
|
+
info "No loop state to clear 无 loop 状态可清除"
|
|
1842
|
+
fi
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1789
1845
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
1790
1846
|
# BRIEF — owner-facing project digest
|
|
1791
1847
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -1812,6 +1868,23 @@ cmd_brief() {
|
|
|
1812
1868
|
[[ -f "$latest" ]] && cat "$latest"
|
|
1813
1869
|
}
|
|
1814
1870
|
|
|
1871
|
+
cmd_release() {
|
|
1872
|
+
local script="scripts/release.sh"
|
|
1873
|
+
if [[ ! -f "$script" ]]; then
|
|
1874
|
+
err "scripts/release.sh not found — run this command from the roll project root."
|
|
1875
|
+
exit 1
|
|
1876
|
+
fi
|
|
1877
|
+
# Sync CHANGELOG.md before releasing, using the configured agent
|
|
1878
|
+
local last_tag; last_tag=$(git tag --sort=-version:refname | grep "^v" | head -1)
|
|
1879
|
+
if [[ -n "$last_tag" ]] && ! git diff "${last_tag}..HEAD" --name-only | grep -q "CHANGELOG.md"; then
|
|
1880
|
+
info "CHANGELOG.md not updated since ${last_tag}, syncing via $(_project_agent)..."
|
|
1881
|
+
_agent_run_skill "roll-.changelog"
|
|
1882
|
+
fi
|
|
1883
|
+
bash "$script" "$@"
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
1887
|
+
|
|
1815
1888
|
_dashboard() {
|
|
1816
1889
|
local project_path; project_path=$(pwd -P)
|
|
1817
1890
|
local project_name; project_name=$(basename "$project_path")
|
|
@@ -1841,7 +1914,8 @@ _dashboard() {
|
|
|
1841
1914
|
fi
|
|
1842
1915
|
|
|
1843
1916
|
echo ""
|
|
1844
|
-
echo "
|
|
1917
|
+
echo " loop <on|off|now|status|resume|reset> · brief · agent use <name> · release"
|
|
1918
|
+
echo " setup · update · init · status · peer · help"
|
|
1845
1919
|
echo ""
|
|
1846
1920
|
}
|
|
1847
1921
|
|
|
@@ -1867,9 +1941,10 @@ usage() {
|
|
|
1867
1941
|
echo " init [Project] Create AGENTS.md + BACKLOG.md + docs/ 初始化项目工作流文件"
|
|
1868
1942
|
echo " status [Diagnostic] Show current state 显示当前状态"
|
|
1869
1943
|
echo " peer [Peer Review] Cross-agent negotiation 跨 Agent 协商对审"
|
|
1870
|
-
echo " loop <on|off|now|status> [Autonomous] Manage scheduled BACKLOG executor 管理自主执行循环"
|
|
1944
|
+
echo " loop <on|off|now|status|resume|reset> [Autonomous] Manage scheduled BACKLOG executor 管理自主执行循环"
|
|
1871
1945
|
echo " brief [Digest] Show latest owner brief (regenerate if stale) 展示最新简报"
|
|
1872
1946
|
echo " agent [use <name>|list] [Config] Per-project agent selection 切换项目 agent"
|
|
1947
|
+
echo " release [Publish] Sync changelog + version bump + npm publish 同步日志并发版"
|
|
1873
1948
|
echo ""
|
|
1874
1949
|
echo "Examples / 示例:"
|
|
1875
1950
|
echo " roll setup # New machine: first-time install 新机器首次安装"
|
|
@@ -1894,6 +1969,7 @@ main() {
|
|
|
1894
1969
|
loop) cmd_loop "$@" ;;
|
|
1895
1970
|
brief) cmd_brief "$@" ;;
|
|
1896
1971
|
agent) cmd_agent "$@" ;;
|
|
1972
|
+
release) cmd_release "$@" ;;
|
|
1897
1973
|
version|--version|-v) echo "roll v${VERSION}" ;;
|
|
1898
1974
|
help|--help|-h) usage ;;
|
|
1899
1975
|
"") [[ -f "BACKLOG.md" ]] && _dashboard || { usage; _show_changelog; } ;;
|
|
@@ -1950,6 +2026,12 @@ _notify_update() {
|
|
|
1950
2026
|
[[ -f "$cache" ]] || return
|
|
1951
2027
|
local latest; latest=$(awk '{print $2}' "$cache" 2>/dev/null || true)
|
|
1952
2028
|
[[ -z "$latest" || "$latest" == "$VERSION" ]] && return
|
|
2029
|
+
local newer; newer=$(printf '%s\n%s\n' "$VERSION" "$latest" | sort -V | tail -1)
|
|
2030
|
+
if [[ "$newer" == "$VERSION" ]]; then
|
|
2031
|
+
# Running version is newer than cached — stale cache, clear it
|
|
2032
|
+
rm -f "$cache"
|
|
2033
|
+
return
|
|
2034
|
+
fi
|
|
1953
2035
|
echo ""
|
|
1954
2036
|
warn "v${latest} available — run 'roll update' to upgrade 有新版本 v${latest} — 运行 'roll update' 升级"
|
|
1955
2037
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seanyao/roll",
|
|
3
|
-
"version": "2026.510.
|
|
3
|
+
"version": "2026.510.7",
|
|
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"
|
|
@@ -144,18 +144,8 @@ roll-.dream runs **locally** — it reads the local codebase directly.
|
|
|
144
144
|
|
|
145
145
|
### Local cron (default)
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
0 1 * * * cd /path/to/project && claude -p "$(cat ~/.roll/skills/roll-.dream/SKILL.md)" >> ~/.shared/roll/dream/cron.log 2>&1
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
Installed automatically via `roll loop install` alongside roll-loop.
|
|
153
|
-
The agent command is read from `~/.roll/config.yaml → loop.primary_agent`.
|
|
154
|
-
|
|
155
|
-
### Agent with native scheduling support
|
|
156
|
-
|
|
157
|
-
If your agent (Claude Code, opencode, etc.) supports scheduled prompts
|
|
158
|
-
natively, prefer that over cron for cleaner lifecycle management.
|
|
147
|
+
Installed automatically via `roll loop on` alongside roll-loop and roll-brief.
|
|
148
|
+
The cron entry is generated using the configured agent — no manual cron editing needed.
|
|
159
149
|
|
|
160
150
|
## Failure Handling
|
|
161
151
|
|
|
@@ -150,13 +150,8 @@ BACKLOG state and git history directly.
|
|
|
150
150
|
|
|
151
151
|
### Local cron (daily morning)
|
|
152
152
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
0 8 * * * cd /path/to/project && claude -p "$(cat ~/.roll/skills/roll-brief/SKILL.md)"
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Installed automatically via `roll loop install` alongside roll-loop and
|
|
159
|
-
roll-.dream. The agent command respects `~/.roll/config.yaml → loop.primary_agent`.
|
|
153
|
+
Installed automatically via `roll loop on` alongside roll-loop and roll-.dream.
|
|
154
|
+
The cron entry is generated using the configured agent — no manual cron editing needed.
|
|
160
155
|
|
|
161
156
|
### Triggered by roll-loop
|
|
162
157
|
|
|
@@ -517,6 +517,9 @@ git push
|
|
|
517
517
|
|
|
518
518
|
### Phase 12: Report & Celebrate
|
|
519
519
|
|
|
520
|
+
**Before reporting, run `$roll-.changelog`** to sync completed Story to CHANGELOG.md.
|
|
521
|
+
This is mandatory — release notes depend on it.
|
|
522
|
+
|
|
520
523
|
```
|
|
521
524
|
✅ Pushed to GitHub: origin/main
|
|
522
525
|
🚀 Deployed: <url>
|
|
@@ -601,7 +604,7 @@ Before creating any file or directory:
|
|
|
601
604
|
- [ ] **Verification Gate passed** (fresh evidence for tests, build, deploy, no regression)
|
|
602
605
|
- [ ] **BACKLOG.md index status updated** (📋 → ✅, REQUIRED)
|
|
603
606
|
- [ ] **`docs/features/<feature>.md` US section updated** (Completed date + [x] ACs, REQUIRED)
|
|
604
|
-
- [ ] **CHANGELOG.md updated** via `$roll-.changelog`
|
|
607
|
+
- [ ] **CHANGELOG.md updated** via `$roll-.changelog` (REQUIRED)
|
|
605
608
|
- [ ] Summary reported to user
|
|
606
609
|
|
|
607
610
|
---
|
package/skills/roll-fix/SKILL.md
CHANGED
|
@@ -174,47 +174,20 @@ cannot fulfill these requirements.
|
|
|
174
174
|
|
|
175
175
|
### Local cron (default)
|
|
176
176
|
|
|
177
|
-
Install once with `roll loop
|
|
177
|
+
Install once with `roll loop on` — it reads the configured agent from
|
|
178
|
+
`.roll.yaml` or `~/.roll/config.yaml` and writes the correct cron entry
|
|
179
|
+
automatically. No agent-specific command needed.
|
|
178
180
|
|
|
179
181
|
```bash
|
|
180
|
-
#
|
|
181
|
-
|
|
182
|
+
roll loop on # install cron for loop + dream + brief
|
|
183
|
+
roll loop off # remove cron entries
|
|
184
|
+
roll loop status # show current state
|
|
182
185
|
```
|
|
183
186
|
|
|
184
|
-
The agent invoked (`claude`, `kimi`, `deepseek`, etc.) is read from
|
|
185
|
-
`~/.roll/config.yaml → loop.primary_agent`. The command is agent-agnostic:
|
|
186
|
-
|
|
187
|
-
```bash
|
|
188
|
-
# claude
|
|
189
|
-
claude -p "$(cat ~/.roll/skills/roll-loop/SKILL.md)"
|
|
190
|
-
|
|
191
|
-
# kimi
|
|
192
|
-
kimi --quiet "$(cat ~/.roll/skills/roll-loop/SKILL.md)"
|
|
193
|
-
|
|
194
|
-
# deepseek
|
|
195
|
-
deepseek "$(cat ~/.roll/skills/roll-loop/SKILL.md)"
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Agent with native scheduling support
|
|
199
|
-
|
|
200
|
-
Some agents support scheduled prompts natively (e.g., Claude Code hooks,
|
|
201
|
-
opencode scheduled tasks). If your agent supports it, prefer that over cron
|
|
202
|
-
— the agent handles its own lifecycle and the setup is cleaner.
|
|
203
|
-
|
|
204
|
-
Consult your agent's documentation for scheduling configuration.
|
|
205
|
-
|
|
206
187
|
### Manual run (for testing)
|
|
207
188
|
|
|
208
189
|
```bash
|
|
209
|
-
roll loop
|
|
210
|
-
roll loop status # show current state without running
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Local cron
|
|
214
|
-
|
|
215
|
-
```bash
|
|
216
|
-
# Every hour
|
|
217
|
-
0 * * * * cd /path/to/project && claude -p "$(cat ~/.roll/skills/roll-loop/SKILL.md)" >> ~/.shared/roll/loop/cron.log 2>&1
|
|
190
|
+
roll loop now # execute one cycle immediately
|
|
218
191
|
```
|
|
219
192
|
|
|
220
193
|
## Integration Map
|
|
@@ -170,12 +170,13 @@ If serve mode is available, prefer HTTP transport over direct CLI invocation.
|
|
|
170
170
|
|
|
171
171
|
| Peer | Non-interactive command | Reliability | Notes |
|
|
172
172
|
|------|------------------------|-------------|-------|
|
|
173
|
-
| `claude` | `claude -p "<prompt>"` | ✅
|
|
174
|
-
| `deepseek` | `deepseek "<prompt>"` | ✅
|
|
173
|
+
| `claude` | `claude -p "<prompt>"` | ✅ Verified | Native, stable |
|
|
174
|
+
| `deepseek` | `deepseek "<prompt>"` | ✅ Verified | No TTY dependency |
|
|
175
175
|
| `deepseek` (serve) | `curl localhost:<port>/v1/...` | ✅ High | Start with `deepseek serve --http`; preferred over direct CLI |
|
|
176
|
-
| `kimi` | `kimi --quiet "<prompt>"` |
|
|
177
|
-
| `
|
|
178
|
-
| `
|
|
176
|
+
| `kimi` | `kimi --quiet -p "<prompt>"` | ✅ Verified | `--quiet` is alias for `--print --output-format text --final-message-only`; prompt via `-p` |
|
|
177
|
+
| `pi` | `pi -p "<prompt>"` | ✅ Verified | Clean non-interactive output |
|
|
178
|
+
| `opencode` | `opencode run "<prompt>"` | ✅ Verified | Works non-interactively |
|
|
179
|
+
| `codex` | `codex exec "<prompt>"` | ⚠️ Auth required | Token must be valid; re-login with `codex login` if expired |
|
|
179
180
|
|
|
180
181
|
**CLI vs. API Key**: `claude`, `deepseek`, `kimi`, `codex` CLIs authenticate via existing subscription accounts — no separate API key required. This is the primary advantage of CLI transport over the MCP/HTTP approach.
|
|
181
182
|
|