@seanyao/roll 2026.510.5 → 2026.510.6

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.5"
7
+ VERSION="2026.510.6"
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 --mode text "$prompt" 2>"$stderr_log" || true)"
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"
@@ -1660,9 +1669,12 @@ _agent_run_skill() {
1660
1669
  [[ -f "$skill_file" ]] || { err "Skill not found: ${skill}"; return 1; }
1661
1670
  case "$agent" in
1662
1671
  claude) claude -p "$(cat "$skill_file")" ;;
1663
- kimi) kimi --quiet "$(cat "$skill_file")" ;;
1672
+ kimi) kimi --quiet -p "$(cat "$skill_file")" ;;
1664
1673
  deepseek) deepseek "$(cat "$skill_file")" ;;
1665
- *) warn "Unknown agent '${agent}', falling back to claude"; claude -p "$(cat "$skill_file")" ;;
1674
+ pi) pi -p "$(cat "$skill_file")" ;;
1675
+ codex) codex exec --json --output-last-message "$(cat "$skill_file")" ;;
1676
+ opencode) opencode run "$(cat "$skill_file")" ;;
1677
+ *) err "Unknown agent '${agent}'. Run: roll agent use <claude|kimi|deepseek|pi|codex|opencode>"; return 1 ;;
1666
1678
  esac
1667
1679
  }
1668
1680
 
@@ -1671,10 +1683,10 @@ cmd_agent() {
1671
1683
  case "$subcmd" in
1672
1684
  use)
1673
1685
  local name="${1:-}"
1674
- [[ -z "$name" ]] && { err "Usage: roll agent use <claude|kimi|deepseek>"; exit 1; }
1686
+ [[ -z "$name" ]] && { err "Usage: roll agent use <claude|kimi|deepseek|pi|codex|opencode>"; exit 1; }
1675
1687
  command -v "$name" &>/dev/null || warn "${name} not found in PATH — setting anyway 未找到,仍写入配置"
1676
1688
  if [[ -f ".roll.yaml" ]] && grep -q "^agent:" .roll.yaml; then
1677
- sed -i "s/^agent:.*/agent: ${name}/" .roll.yaml
1689
+ local tmp; tmp=$(mktemp) && sed "s/^agent:.*/agent: ${name}/" .roll.yaml > "$tmp" && mv "$tmp" .roll.yaml
1678
1690
  else
1679
1691
  echo "agent: ${name}" >> .roll.yaml
1680
1692
  fi
@@ -1714,6 +1726,20 @@ _LOOP_TAG="# roll-loop"
1714
1726
  _LOOP_STATE="${HOME}/.shared/roll/loop/state.yaml"
1715
1727
  _LOOP_ALERT="${HOME}/.shared/roll/loop/ALERT.md"
1716
1728
 
1729
+ _agent_skill_cmd() {
1730
+ local skill_path="$1"
1731
+ local agent; agent=$(_project_agent)
1732
+ case "$agent" in
1733
+ claude) echo "claude -p \"\$(cat '${skill_path}')\"" ;;
1734
+ kimi) echo "kimi --quiet -p \"\$(cat '${skill_path}')\"" ;;
1735
+ deepseek) echo "deepseek \"\$(cat '${skill_path}')\"" ;;
1736
+ pi) echo "pi -p \"\$(cat '${skill_path}')\"" ;;
1737
+ codex) echo "codex exec --json --output-last-message \"\$(cat '${skill_path}')\"" ;;
1738
+ opencode) echo "opencode run \"\$(cat '${skill_path}')\"" ;;
1739
+ *) err "Unknown agent '${agent}'. Run: roll agent use <claude|kimi|deepseek|pi|codex|opencode>"; return 1 ;;
1740
+ esac
1741
+ }
1742
+
1717
1743
  cmd_loop() {
1718
1744
  local subcmd="${1:-status}"; shift || true
1719
1745
  case "$subcmd" in
@@ -1721,7 +1747,9 @@ cmd_loop() {
1721
1747
  off) _loop_off ;;
1722
1748
  now) _loop_now ;;
1723
1749
  status) _loop_status ;;
1724
- *) err "Usage: roll loop <on|off|now|status>"; exit 1 ;;
1750
+ resume) _loop_resume ;;
1751
+ reset) _loop_reset ;;
1752
+ *) err "Usage: roll loop <on|off|now|status|resume|reset>"; exit 1 ;;
1725
1753
  esac
1726
1754
  }
1727
1755
 
@@ -1737,9 +1765,9 @@ _loop_on() {
1737
1765
  mkdir -p ~/.shared/roll/{loop,dream,brief}
1738
1766
 
1739
1767
  local loop_cmd dream_cmd brief_cmd
1740
- loop_cmd="cd \"${project_path}\" && ${agent} -p \"\$(cat ${sd}/roll-loop/SKILL.md)\" >> ~/.shared/roll/loop/cron.log 2>&1"
1741
- dream_cmd="cd \"${project_path}\" && ${agent} -p \"\$(cat ${sd}/roll-.dream/SKILL.md)\" >> ~/.shared/roll/dream/cron.log 2>&1"
1742
- brief_cmd="cd \"${project_path}\" && ${agent} -p \"\$(cat ${sd}/roll-brief/SKILL.md)\" >> ~/.shared/roll/brief/cron.log 2>&1"
1768
+ loop_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-loop/SKILL.md") >> ~/.shared/roll/loop/cron.log 2>&1"
1769
+ dream_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-.dream/SKILL.md") >> ~/.shared/roll/dream/cron.log 2>&1"
1770
+ brief_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-brief/SKILL.md") >> ~/.shared/roll/brief/cron.log 2>&1"
1743
1771
 
1744
1772
  (
1745
1773
  crontab -l 2>/dev/null
@@ -1786,6 +1814,26 @@ _loop_status() {
1786
1814
  echo ""
1787
1815
  }
1788
1816
 
1817
+ _loop_resume() {
1818
+ if [[ ! -f "$_LOOP_STATE" ]]; then
1819
+ warn "No loop state found — nothing to resume 未找到 loop 状态,无需恢复"; return 0
1820
+ fi
1821
+ if grep -q "status: running" "$_LOOP_STATE" 2>/dev/null; then
1822
+ warn "Loop already running loop 正在运行中"; return 0
1823
+ fi
1824
+ info "Resuming loop from last state... 正在从上次状态恢复..."
1825
+ _agent_run_skill "roll-loop"
1826
+ }
1827
+
1828
+ _loop_reset() {
1829
+ if [[ -f "$_LOOP_STATE" ]]; then
1830
+ rm -f "$_LOOP_STATE"
1831
+ ok "Loop state cleared — will start fresh on next run loop 状态已清除,下次运行将重新开始"
1832
+ else
1833
+ info "No loop state to clear 无 loop 状态可清除"
1834
+ fi
1835
+ }
1836
+
1789
1837
  # ═══════════════════════════════════════════════════════════════════════════════
1790
1838
  # BRIEF — owner-facing project digest
1791
1839
  # ═══════════════════════════════════════════════════════════════════════════════
@@ -1812,6 +1860,23 @@ cmd_brief() {
1812
1860
  [[ -f "$latest" ]] && cat "$latest"
1813
1861
  }
1814
1862
 
1863
+ cmd_release() {
1864
+ local script="scripts/release.sh"
1865
+ if [[ ! -f "$script" ]]; then
1866
+ err "scripts/release.sh not found — run this command from the roll project root."
1867
+ exit 1
1868
+ fi
1869
+ # Sync CHANGELOG.md before releasing, using the configured agent
1870
+ local last_tag; last_tag=$(git tag --sort=-version:refname | grep "^v" | head -1)
1871
+ if [[ -n "$last_tag" ]] && ! git diff "${last_tag}..HEAD" --name-only | grep -q "CHANGELOG.md"; then
1872
+ info "CHANGELOG.md not updated since ${last_tag}, syncing via $(_project_agent)..."
1873
+ _agent_run_skill "roll-.changelog"
1874
+ fi
1875
+ bash "$script" "$@"
1876
+ }
1877
+
1878
+ # ─────────────────────────────────────────────────────────────────────────────
1879
+
1815
1880
  _dashboard() {
1816
1881
  local project_path; project_path=$(pwd -P)
1817
1882
  local project_name; project_name=$(basename "$project_path")
@@ -1841,7 +1906,7 @@ _dashboard() {
1841
1906
  fi
1842
1907
 
1843
1908
  echo ""
1844
- echo " roll loop on|off|now|status · roll brief · roll agent use <name>"
1909
+ echo " roll loop on|off|now|status|resume|reset · roll brief · roll agent use <name>"
1845
1910
  echo ""
1846
1911
  }
1847
1912
 
@@ -1867,7 +1932,7 @@ usage() {
1867
1932
  echo " init [Project] Create AGENTS.md + BACKLOG.md + docs/ 初始化项目工作流文件"
1868
1933
  echo " status [Diagnostic] Show current state 显示当前状态"
1869
1934
  echo " peer [Peer Review] Cross-agent negotiation 跨 Agent 协商对审"
1870
- echo " loop <on|off|now|status> [Autonomous] Manage scheduled BACKLOG executor 管理自主执行循环"
1935
+ echo " loop <on|off|now|status|resume|reset> [Autonomous] Manage scheduled BACKLOG executor 管理自主执行循环"
1871
1936
  echo " brief [Digest] Show latest owner brief (regenerate if stale) 展示最新简报"
1872
1937
  echo " agent [use <name>|list] [Config] Per-project agent selection 切换项目 agent"
1873
1938
  echo ""
@@ -1894,6 +1959,7 @@ main() {
1894
1959
  loop) cmd_loop "$@" ;;
1895
1960
  brief) cmd_brief "$@" ;;
1896
1961
  agent) cmd_agent "$@" ;;
1962
+ release) cmd_release "$@" ;;
1897
1963
  version|--version|-v) echo "roll v${VERSION}" ;;
1898
1964
  help|--help|-h) usage ;;
1899
1965
  "") [[ -f "BACKLOG.md" ]] && _dashboard || { usage; _show_changelog; } ;;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanyao/roll",
3
- "version": "2026.510.5",
3
+ "version": "2026.510.6",
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
- ```bash
148
- # Run at 01:00 every night (adjust to your timezone)
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
- ```bash
154
- # 08:00 every morning (adjust to your timezone)
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
  ---
@@ -320,6 +320,8 @@ Change the Status of the corresponding row from `📋 Todo` to `✅ Done`.
320
320
 
321
321
  ### 12. Update Changelog
322
322
 
323
+ **Mandatory** — release notes depend on this step. Do not skip.
324
+
323
325
  ```bash
324
326
  $roll-.changelog
325
327
  ```
@@ -174,47 +174,20 @@ cannot fulfill these requirements.
174
174
 
175
175
  ### Local cron (default)
176
176
 
177
- Install once with `roll loop install`:
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
- # What roll loop install writes to crontab:
181
- 0 * * * * cd /path/to/project && claude -p "$(cat ~/.roll/skills/roll-loop/SKILL.md)" >> ~/.shared/roll/loop/cron.log 2>&1
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 run # execute one cycle immediately
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>"` | ✅ High | Native, stable |
174
- | `deepseek` | `deepseek "<prompt>"` | ✅ Good | No TTY dependency |
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>"` | ⚠️ Unverified | Verify non-interactive support before use |
177
- | `codex` | `codex exec --json --output-last-message "<prompt>"` | ⚠️ Unstable | Known CI failures due to Ink/TTY (issues [#1080](https://github.com/openai/codex/issues/1080), [#1340](https://github.com/openai/codex/issues/1340)); use only as fallback |
178
- | `pi` | `pi -p "<prompt>"` | ⚠️ Unverified | Verify non-interactive support before use |
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