@seanyao/roll 2.604.1 → 2.604.2

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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## v2.604.2
4
+
5
+ ### 精简
6
+
7
+ - **自动简报功能下线(FIX-195)** — 不再后台定时生成每日简报;需要时手动运行 `roll brief` 即可,过往简报都保留
8
+
9
+ ### 稳定性
10
+
11
+ - **一条坏记录不再拖垮整个自动循环(FIX-193)** — 以前运行历史里出现一条损坏记录,会让 `roll loop` 整个起不来;现在自动跳过坏记录、照常运行
12
+
3
13
  ## v2.604.1
4
14
 
5
15
  ### PR Loop 重构
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="2.604.1"
7
+ VERSION="2.604.2"
8
8
  ROLL_HOME="${ROLL_HOME:-${HOME}/.roll}"
9
9
  ROLL_CONFIG="${ROLL_HOME}/config.yaml"
10
10
  ROLL_GLOBAL="${ROLL_HOME}/conventions/global"
@@ -1092,8 +1092,6 @@ editor: ${EDITOR:-vim}
1092
1092
  # loop_minute: 5 # omit to auto-derive from project hash
1093
1093
  loop_dream_hour: 3
1094
1094
  # loop_dream_minute: 10 # omit to auto-derive
1095
- loop_brief_hour: 9
1096
- # loop_brief_minute: 15 # omit to auto-derive
1097
1095
  primary_agent: claude
1098
1096
  YAML
1099
1097
  ok "$(msg shared.created_roll_config_yaml)"
@@ -5752,8 +5750,6 @@ loop_schedule.period_minutes|project|nested:loop_schedule|1|1440|60
5752
5750
  loop_schedule.offset_minute|project|nested:loop_schedule|0|59|0
5753
5751
  loop_dream_hour|global|flat|0|23|3
5754
5752
  loop_dream_minute|global|flat|0|59|-
5755
- loop_brief_hour|global|flat|0|23|9
5756
- loop_brief_minute|global|flat|0|59|-
5757
5753
  EOF
5758
5754
  }
5759
5755
 
@@ -5892,10 +5888,10 @@ Usage: roll config <key> print current value + source
5892
5888
  roll config --list list all loop schedule keys
5893
5889
  roll config <key> <value> [--global|--project] set a value
5894
5890
  统一调度配置
5895
- Read / list / set the loop, dream and brief schedule keys without hand-editing
5891
+ Read / list / set the loop and dream schedule keys without hand-editing
5896
5892
  yaml. Default write scope is --project (.roll/local.yaml); --global writes
5897
5893
  ~/.roll/config.yaml.
5898
- 读 / 列 / 写 loop、dream、brief 调度 key,免去手工编辑 yaml。默认写 --project
5894
+ 读 / 列 / 写 loop、dream 调度 key,免去手工编辑 yaml。默认写 --project
5899
5895
  (.roll/local.yaml);--global 写 ~/.roll/config.yaml。
5900
5896
 
5901
5897
  Supported keys (range):
@@ -5905,14 +5901,11 @@ Supported keys (range):
5905
5901
  loop_schedule.offset_minute 0-59 minute offset within the period
5906
5902
  loop_dream_hour 0-23 dream daily fire hour
5907
5903
  loop_dream_minute 0-59 dream daily fire minute
5908
- loop_brief_hour 0-23 brief daily fire hour
5909
- loop_brief_minute 0-59 brief daily fire minute
5910
5904
 
5911
5905
  Compact facades (write multiple keys at once):
5912
5906
  roll config loop-window 9-18 loop_active_start + loop_active_end
5913
5907
  roll config loop-schedule 30/7 period_minutes + offset_minute
5914
5908
  roll config dream-time 03:20 loop_dream_hour + loop_dream_minute
5915
- roll config brief-time 09:15 loop_brief_hour + loop_brief_minute
5916
5909
 
5917
5910
  Examples:
5918
5911
  roll config loop_dream_hour
@@ -6012,11 +6005,12 @@ _config_loop_schedule() {
6012
6005
  return 0
6013
6006
  }
6014
6007
 
6015
- # US-LOOP-035: `roll config dream-time <HH:MM>` / `brief-time <HH:MM>` — compact
6016
- # facade writing loop_<svc>_hour + loop_<svc>_minute in one shot. With no value,
6017
- # prints the current effective time + source. HH ∈ [0,23], MM ∈ [0,59].
6008
+ # US-LOOP-035: `roll config dream-time <HH:MM>` compact facade writing
6009
+ # loop_<svc>_hour + loop_<svc>_minute in one shot. With no value, prints the
6010
+ # current effective time + source. HH ∈ [0,23], MM ∈ [0,59].
6018
6011
  # These keys are global-scoped, so writes land in ~/.roll/config.yaml.
6019
- # _config_daily_time <svc> <value> svc {dream, brief}
6012
+ # FIX-195: brief retired — svc is {dream} (the helper stays generic).
6013
+ # _config_daily_time <svc> <value>
6020
6014
  _config_daily_time() {
6021
6015
  local svc="$1" value="$2"
6022
6016
  local hour_key="loop_${svc}_hour" min_key="loop_${svc}_minute"
@@ -6115,8 +6109,9 @@ cmd_config() {
6115
6109
  [[ $_rc -eq 0 && -n "$value" ]] && _config_reload_schedule
6116
6110
  return $_rc
6117
6111
  ;;
6118
- dream-time|brief-time)
6119
- # dream/brief schedule keys are global-scoped (~/.roll/config.yaml).
6112
+ dream-time)
6113
+ # FIX-195: brief-time retired with the brief loop; dream-time is the only
6114
+ # daily schedule facade. The key is global-scoped (~/.roll/config.yaml).
6120
6115
  local fscope="$scope"; [[ -z "$fscope" ]] && fscope="global"
6121
6116
  ROLL_CFG_SCOPE="$fscope"
6122
6117
  local _rc
@@ -6171,7 +6166,7 @@ cmd_config() {
6171
6166
  fi
6172
6167
  _config_set "$key" "$value" "$file"
6173
6168
  ok "✓ set $key = $value in $file"
6174
- # US-LOOP-036: every recognized config key is a loop/dream/brief schedule key
6169
+ # US-LOOP-036: every recognized config key is a loop/dream schedule key
6175
6170
  # (display-only keys are out of scope for this command), so a successful write
6176
6171
  # always reloads the launchd plists.
6177
6172
  _config_reload_schedule
@@ -9658,9 +9653,10 @@ _install_launchd_plists() {
9658
9653
  local shared="${_SHARED_ROOT}"
9659
9654
 
9660
9655
  mkdir -p "$_LAUNCHD_DIR"
9661
- mkdir -p "${shared}/loop" "${shared}/dream" "${shared}/brief" "${shared}/pr" "${shared}/ci" "${shared}/alert"
9656
+ # FIX-194/FIX-195: brief/ci/alert loops retired — only loop/dream/pr remain.
9657
+ mkdir -p "${shared}/loop" "${shared}/dream" "${shared}/pr"
9662
9658
 
9663
- local active_start active_end dream_hour dream_minute brief_hour brief_minute loop_period loop_offset
9659
+ local active_start active_end dream_hour dream_minute loop_period loop_offset
9664
9660
  local _aw; _aw=$(_loop_read_active_window "$project_path")
9665
9661
  active_start="${_aw%% *}"; active_end="${_aw##* }"
9666
9662
  # US-LOOP-012: use _loop_schedule_spec instead of raw loop_minute
@@ -9669,8 +9665,6 @@ _install_launchd_plists() {
9669
9665
  loop_offset="${loop_spec##* }"
9670
9666
  dream_hour=$(_config_read_int "loop_dream_hour" "3")
9671
9667
  dream_minute=$(_config_read_int "loop_dream_minute" "$(_loop_derive_minute "$project_path" 2)")
9672
- brief_hour=$(_config_read_int "loop_brief_hour" "9")
9673
- brief_minute=$(_config_read_int "loop_brief_minute" "$(_loop_derive_minute "$project_path" 4)")
9674
9668
 
9675
9669
  # FIX-054: terminal preference removed — runner always uses Terminal.app.
9676
9670
 
@@ -9840,7 +9834,7 @@ cmd_loop() {
9840
9834
  *) cat <<'HELP'
9841
9835
  Usage: roll loop <on|off|now|test|status|monitor|runs|log|story|events|attach|mute|unmute|pause|resume|reset|gc|branches>
9842
9836
 
9843
- on Install launchd scheduler (loop + dream + brief + pr + ci + alert)
9837
+ on Install launchd scheduler (loop + dream + pr)
9844
9838
  off Remove launchd scheduler
9845
9839
  now Run one cycle immediately
9846
9840
  test Quick smoke test (tmux/popup/stream chain)
@@ -9885,7 +9879,7 @@ _loop_on() {
9885
9879
  local project_path; project_path=$(pwd -P)
9886
9880
  local agent; agent=$(_project_agent)
9887
9881
 
9888
- local active_start active_end loop_minute dream_hour dream_minute brief_hour brief_minute
9882
+ local active_start active_end loop_minute dream_hour dream_minute
9889
9883
  local _aw; _aw=$(_loop_read_active_window "$project_path")
9890
9884
  active_start="${_aw%% *}"; active_end="${_aw##* }"
9891
9885
  # US-LOOP-011: read schedule spec from project or global config
@@ -9900,8 +9894,6 @@ _loop_on() {
9900
9894
  loop_sched_zh=$(_loop_schedule_desc "$loop_period" "$loop_offset" zh)
9901
9895
  dream_hour=$(_config_read_int "loop_dream_hour" "3")
9902
9896
  dream_minute=$(_config_read_int "loop_dream_minute" "$(_loop_derive_minute "$project_path" 2)")
9903
- brief_hour=$(_config_read_int "loop_brief_hour" "9")
9904
- brief_minute=$(_config_read_int "loop_brief_minute" "$(_loop_derive_minute "$project_path" 4)")
9905
9897
 
9906
9898
  if [[ "$(uname)" == "Darwin" ]]; then
9907
9899
  _install_launchd_plists "$project_path" >/dev/null
@@ -9936,7 +9928,6 @@ _loop_on() {
9936
9928
  msg loop.roll_loop_s_active_02d_00 \
9937
9929
  "$loop_sched_en" "$active_start" "$active_end" "$loop_sched_zh" "$active_start" "$active_end"
9938
9930
  msg loop.roll_dream_daily_at_02d_02d "$dream_hour" "$dream_minute" "$dream_hour" "$dream_minute"
9939
- msg loop.roll_brief_daily_at_02d_02d "$brief_hour" "$brief_minute" "$brief_hour" "$brief_minute"
9940
9931
  echo " • Agent: ${agent} (change: roll agent use <name>)"
9941
9932
  return 0
9942
9933
  fi
@@ -9947,29 +9938,26 @@ _loop_on() {
9947
9938
  warn "$(msg loop.loop_already_enabled_for_this_project_2)"; return 0
9948
9939
  fi
9949
9940
 
9950
- mkdir -p "${_SHARED_ROOT}/loop" "${_SHARED_ROOT}/dream" "${_SHARED_ROOT}/brief"
9941
+ mkdir -p "${_SHARED_ROOT}/loop" "${_SHARED_ROOT}/dream"
9951
9942
 
9952
9943
  # FIX-052: per-project cron logs so concurrent projects don't interleave.
9953
9944
  local slug; slug=$(_project_slug "$project_path")
9954
- local loop_cmd dream_cmd brief_cmd
9945
+ local loop_cmd dream_cmd
9955
9946
  loop_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-loop/SKILL.md") >> ${_SHARED_ROOT}/loop/cron-${slug}.log 2>&1"
9956
- # IDEA-051: dream/brief cron logs are project-local, mirroring loop (FIX-139).
9957
- mkdir -p "${project_path}/.roll/dream" "${project_path}/.roll/brief"
9947
+ # IDEA-051: dream cron log is project-local, mirroring loop (FIX-139).
9948
+ mkdir -p "${project_path}/.roll/dream"
9958
9949
  dream_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-.dream/SKILL.md") >> ${project_path}/.roll/dream/cron.log 2>&1"
9959
- brief_cmd="cd \"${project_path}\" && $(_agent_skill_cmd "${sd}/roll-brief/SKILL.md") >> ${project_path}/.roll/brief/cron.log 2>&1"
9960
9950
 
9961
9951
  (
9962
9952
  crontab -l 2>/dev/null
9963
9953
  printf "%d * * * * %s %s:%s\n" "$loop_minute" "$loop_cmd" "$_LOOP_TAG" "$project_path"
9964
9954
  printf "%d %d * * * %s %s:%s\n" "$dream_minute" "$dream_hour" "$dream_cmd" "$_LOOP_TAG" "$project_path"
9965
- printf "%d %d * * * %s %s:%s\n" "$brief_minute" "$brief_hour" "$brief_cmd" "$_LOOP_TAG" "$project_path"
9966
9955
  ) | crontab -
9967
9956
 
9968
9957
  ok "$(msg loop.loop_enabled_2)"
9969
9958
  msg loop.roll_loop_s_active_02d_00_2 \
9970
9959
  "$loop_sched_en" "$active_start" "$active_end" "$loop_sched_zh" "$active_start" "$active_end"
9971
9960
  msg loop.roll_dream_daily_at_02d_02d_2 "$dream_hour" "$dream_minute" "$dream_hour" "$dream_minute"
9972
- msg loop.roll_brief_daily_at_02d_02d_2 "$brief_hour" "$brief_minute" "$brief_hour" "$brief_minute"
9973
9961
  echo " • Agent: ${agent} (change: roll agent use <name>)"
9974
9962
  }
9975
9963
 
@@ -13789,7 +13777,7 @@ _loop_monitor() {
13789
13777
  # Services status (three services on macOS, single on Linux)
13790
13778
  echo -e "$(msg loop.services ${BOLD} ${NC} ${CYAN} ${agent})"
13791
13779
  if [[ "$(uname)" == "Darwin" ]]; then
13792
- local active_start active_end dream_hour dream_minute brief_hour brief_minute
13780
+ local active_start active_end dream_hour dream_minute
13793
13781
  local _aw; _aw=$(_loop_read_active_window "$project_path")
13794
13782
  active_start="${_aw%% *}"; active_end="${_aw##* }"
13795
13783
  # US-LOOP-013: use schedule spec for display
@@ -13799,17 +13787,16 @@ _loop_monitor() {
13799
13787
  loop_offset="${loop_spec##* }"
13800
13788
  dream_hour=$(_config_read_int "loop_dream_hour" "3")
13801
13789
  dream_minute=$(_config_read_int "loop_dream_minute" "$(_loop_derive_minute "$project_path" 2)")
13802
- brief_hour=$(_config_read_int "loop_brief_hour" "9")
13803
- brief_minute=$(_config_read_int "loop_brief_minute" "$(_loop_derive_minute "$project_path" 4)")
13804
13790
 
13805
- local loop_sched dream_sched brief_sched
13791
+ local loop_sched dream_sched pr_sched
13806
13792
  loop_sched=$(_loop_schedule_desc "$loop_period" "$loop_offset" en)
13807
13793
  loop_sched="${loop_sched} active ${active_start}:00–${active_end}:00"
13808
13794
  dream_sched=$(printf "%02d:%02d" "$dream_hour" "$dream_minute")
13809
- brief_sched=$(printf "%02d:%02d" "$brief_hour" "$brief_minute")
13795
+ # FIX-195: pr is a 5-min PR Loop (StartInterval=300); brief was retired.
13796
+ pr_sched="every 5m"
13810
13797
 
13811
13798
  local svcs=("loop" "dream" "pr")
13812
- local scheds=("$loop_sched" "$dream_sched" "$brief_sched")
13799
+ local scheds=("$loop_sched" "$dream_sched" "$pr_sched")
13813
13800
  for i in "${!svcs[@]}"; do
13814
13801
  local svc="${svcs[$i]}" schedule="${scheds[$i]}"
13815
13802
  local state; state=$(_launchd_svc_state "$svc" "$project_path")
@@ -14899,7 +14886,7 @@ _legacy_home() {
14899
14886
  else
14900
14887
  crontab -l 2>/dev/null | grep -q "${_LOOP_TAG}:${project_path}" && loop_state="enabled"
14901
14888
  fi
14902
- local active_start active_end dream_hour dream_minute brief_hour brief_minute
14889
+ local active_start active_end dream_hour dream_minute
14903
14890
  local _aw; _aw=$(_loop_read_active_window "$project_path")
14904
14891
  active_start="${_aw%% *}"; active_end="${_aw##* }"
14905
14892
  # US-LOOP-013: use schedule spec for display
@@ -14909,8 +14896,6 @@ _legacy_home() {
14909
14896
  loop_offset="${loop_spec##* }"
14910
14897
  dream_hour=$(_config_read_int "loop_dream_hour" "3")
14911
14898
  dream_minute=$(_config_read_int "loop_dream_minute" "$(_loop_derive_minute "$project_path" 2)")
14912
- brief_hour=$(_config_read_int "loop_brief_hour" "9")
14913
- brief_minute=$(_config_read_int "loop_brief_minute" "$(_loop_derive_minute "$project_path" 4)")
14914
14899
 
14915
14900
  local loop_badge loop_sched
14916
14901
  loop_sched=$(_loop_schedule_desc "$loop_period" "$loop_offset" en)
@@ -15040,8 +15025,9 @@ _legacy_home() {
15040
15025
  # ── ⑥ Schedules & Last Brief ──────────────────────────────────────────────
15041
15026
  printf " ${BOLD}⏰ Schedules & Last Brief${NC}\n"
15042
15027
  local loop_sched_short; loop_sched_short=$(_loop_schedule_desc "$loop_period" "$loop_offset" en)
15043
- printf " %s · dream %02d:%02d · brief %02d:%02d\n" \
15044
- "$loop_sched_short" "$dream_hour" "$dream_minute" "$brief_hour" "$brief_minute"
15028
+ # FIX-195: brief loop retired schedule line shows loop + dream only.
15029
+ printf " %s · dream %02d:%02d\n" \
15030
+ "$loop_sched_short" "$dream_hour" "$dream_minute"
15045
15031
  local latest_brief; latest_brief=$(ls .roll/briefs/*.md 2>/dev/null | sort | tail -1 || true)
15046
15032
  if [[ -n "$latest_brief" ]]; then
15047
15033
  local mod_time now age summary
package/lib/i18n/loop.sh CHANGED
@@ -7,8 +7,6 @@ _i18n_set en loop.roll_loop_s_active_02d_00 " • roll-loop %s active %02d:0
7
7
  _i18n_set zh loop.roll_loop_s_active_02d_00 " • roll-loop %s 有效窗口 %02d:00–%02d:00 %s(active %02d:00–%02d:00)"
8
8
  _i18n_set en loop.roll_dream_daily_at_02d_02d " • roll-.dream daily at %02d:%02d 每天 %02d:%02d"
9
9
  _i18n_set zh loop.roll_dream_daily_at_02d_02d " • roll-.dream daily at %02d:%02d 每天 %02d:%02d"
10
- _i18n_set en loop.roll_brief_daily_at_02d_02d " • roll-brief daily at %02d:%02d 每天 %02d:%02d"
11
- _i18n_set zh loop.roll_brief_daily_at_02d_02d " • roll-brief daily at %02d:%02d 每天 %02d:%02d"
12
10
  _i18n_set en loop.loop_already_enabled_for_this_project_2 "Loop already enabled for this project"
13
11
  _i18n_set zh loop.loop_already_enabled_for_this_project_2 "当前项目 loop 已启用"
14
12
  _i18n_set en loop.loop_enabled_2 "Loop enabled"
@@ -17,8 +15,6 @@ _i18n_set en loop.roll_loop_s_active_02d_00_2 " • roll-loop %s active %02d
17
15
  _i18n_set zh loop.roll_loop_s_active_02d_00_2 " • roll-loop %s 有效窗口 %02d:00–%02d:00 %s(active %02d:00–%02d:00)"
18
16
  _i18n_set en loop.roll_dream_daily_at_02d_02d_2 " • roll-.dream daily at %02d:%02d 每天 %02d:%02d"
19
17
  _i18n_set zh loop.roll_dream_daily_at_02d_02d_2 " • roll-.dream daily at %02d:%02d 每天 %02d:%02d"
20
- _i18n_set en loop.roll_brief_daily_at_02d_02d_2 " • roll-brief daily at %02d:%02d 每天 %02d:%02d"
21
- _i18n_set zh loop.roll_brief_daily_at_02d_02d_2 " • roll-brief daily at %02d:%02d 每天 %02d:%02d"
22
18
  _i18n_set en loop.loop_not_enabled_for_this_project "Loop not enabled for this project"
23
19
  _i18n_set zh loop.loop_not_enabled_for_this_project "当前项目 loop 未启用"
24
20
  _i18n_set en loop.loop_disabled "Loop disabled"
@@ -668,6 +668,12 @@ def load_runs(slug: str) -> Dict[str, Dict[str, Any]]:
668
668
  r = json.loads(line)
669
669
  except Exception:
670
670
  continue
671
+ # FIX-193: a stray line can parse as a bare JSON scalar (e.g. an
672
+ # agent pretty-printed a record across lines and `"FIX-181"` parses
673
+ # as a str) — r.get() then crashes the whole dashboard. Records
674
+ # must be objects; skip anything else.
675
+ if not isinstance(r, dict):
676
+ continue
671
677
  p = r.get("project", "")
672
678
  if p != slug and p != base and not p.startswith(f"{slug}-cycle-"):
673
679
  # String match failed — try path match for old-slug salvage.
@@ -1186,15 +1192,17 @@ def render(events, cron, state, backlog, *, days=3, lang="both", now=None,
1186
1192
  # would duplicate signal without adding info.
1187
1193
  print(eb_zh)
1188
1194
 
1189
- # US-LOOP-036: daily service (dream/brief) next-fire lines, read straight
1190
- # from the launchd plist so they reflect the latest `roll config <svc>-time`
1191
- # reload rather than a stale yaml-derived guess.
1192
- for _svc in ("dream", "brief"):
1195
+ # US-LOOP-036: daily service (dream) next-fire line, read straight from the
1196
+ # launchd plist so it reflects the latest `roll config dream-time` reload
1197
+ # rather than a stale yaml-derived guess.
1198
+ # FIX-194/FIX-195: brief loop retired — dream is the only daily service.
1199
+ for _svc in ("dream",):
1193
1200
  _sl = _daily_schedule_line(_svc, now=now)
1194
1201
  if _sl:
1195
1202
  print(" " + c("dim", _sl))
1196
- # FIX-151: dedicated loop (pr/ci/alert) last-tick age
1197
- for _loop in ("pr", "ci", "alert"):
1203
+ # FIX-151: dedicated loop last-tick age.
1204
+ # FIX-194: ci/alert loops retired — pr is the only dedicated loop tick.
1205
+ for _loop in ("pr",):
1198
1206
  _tl = _tick_age_line(_loop, now=now)
1199
1207
  if _tl:
1200
1208
  print(" " + c("dim", _tl))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanyao/roll",
3
- "version": "2.604.1",
3
+ "version": "2.604.2",
4
4
  "description": "Roll — Roll out features with AI agents",
5
5
  "scripts": {
6
6
  "test": "bash tests/run.sh"