@seanyao/roll 2026.522.1 → 2026.522.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 +17 -0
- package/bin/roll +210 -42
- package/conventions/config.yaml +1 -1
- package/conventions/global/AGENTS.md +1 -1
- package/conventions/global/GEMINI.md +8 -3
- package/conventions/templates/backend-service/GEMINI.md +3 -3
- package/conventions/templates/cli/GEMINI.md +3 -3
- package/conventions/templates/frontend-only/GEMINI.md +3 -3
- package/conventions/templates/fullstack/GEMINI.md +3 -3
- package/lib/__pycache__/model_prices.cpython-314.pyc +0 -0
- package/lib/__pycache__/roll-loop-status.cpython-314.pyc +0 -0
- package/lib/__pycache__/roll_render.cpython-314.pyc +0 -0
- package/lib/model_prices.py +16 -5
- package/lib/roll-loop-status.py +76 -21
- package/lib/roll-peer.py +1 -1
- package/lib/roll-status.py +1 -1
- package/lib/roll_render.py +9 -3
- package/lib/slides/templates/introduction-v3.html +576 -0
- package/package.json +1 -1
- package/skills/roll-deck/SKILL.md +22 -14
- package/skills/roll-design/SKILL.md +86 -0
- package/skills/roll-doctor/SKILL.md +1 -1
- package/skills/roll-onboard/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v2026.522.2
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Roll 改用 Antigravity (`agy`)** — Google 已退役独立 Gemini CLI,agy 是接班产品;老用户重跑 `roll setup` 即可
|
|
8
|
+
|
|
9
|
+
### Improved
|
|
10
|
+
|
|
11
|
+
- **dashboard token 列现在只算 input/output,cache 不再混进来虚抬总量** `[loop]`
|
|
12
|
+
- **`roll loop status` 现在分清「没装 / 装了关了 / 正常」三种状态** — 之前看不出 loop 到底有没有起来 `[loop]`
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **loop 异常中断时未推送的 commit 不再丢** — 自动开成 PR `[loop]`
|
|
17
|
+
- **loop 每小时弹窗不再抢前台焦点** — 后台开 Terminal,不打断你在干的事
|
|
18
|
+
- **`roll loop` 在非 git 目录下不再静默崩溃** `[loop]`
|
|
19
|
+
|
|
3
20
|
## v2026.522.1
|
|
4
21
|
|
|
5
22
|
### Fixed
|
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.522.
|
|
7
|
+
VERSION="2026.522.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"
|
|
@@ -59,6 +59,9 @@ ai_tool_name() {
|
|
|
59
59
|
elif [[ "$bn" == "agent" || "$bn" == "workspace" ]]; then
|
|
60
60
|
bn="$(basename "$(dirname "$dir")" | sed 's/^\.//')"
|
|
61
61
|
fi
|
|
62
|
+
# Antigravity (agy) reuses ~/.gemini/ from the deprecated Gemini CLI for
|
|
63
|
+
# its config dir, so a literal `gemini` basename now identifies agy.
|
|
64
|
+
[[ "$bn" == "gemini" ]] && bn="agy"
|
|
62
65
|
echo "$bn"
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -94,6 +97,123 @@ _is_ai_installed() {
|
|
|
94
97
|
return 1
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
# ─── Spinner: TTY-aware status display for long-running steps (US-REL-003) ───
|
|
101
|
+
# _spin_setup [off]
|
|
102
|
+
# Opens FD 3 for spinner output. Without args: FD 3 → stdout if interactive,
|
|
103
|
+
# else stderr (best-effort visibility for the operator). With "off": FD 3
|
|
104
|
+
# → /dev/null, silencing all _spin output (useful for scripts that drive
|
|
105
|
+
# release.sh in non-interactive contexts but still want exit codes).
|
|
106
|
+
_spin_setup() {
|
|
107
|
+
if [ "${1:-}" = "off" ]; then
|
|
108
|
+
exec 3>/dev/null
|
|
109
|
+
return 0
|
|
110
|
+
fi
|
|
111
|
+
if [ -t 1 ]; then
|
|
112
|
+
# Interactive: spinner shares stdout with normal program output.
|
|
113
|
+
exec 3>&1
|
|
114
|
+
else
|
|
115
|
+
# Non-interactive (stdout redirected to file / piped): route the spinner
|
|
116
|
+
# trail to stderr so it stays visible in CI logs and never pollutes the
|
|
117
|
+
# caller's redirected stdout (e.g. > release_notes.txt). FD 3 will be
|
|
118
|
+
# plain-text mode whenever stderr is also not a TTY.
|
|
119
|
+
exec 3>&2
|
|
120
|
+
fi
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# _spin <label> <cmd> [args...]
|
|
124
|
+
# Runs cmd with a status indicator written to FD 3 only. cmd's own
|
|
125
|
+
# stdout (FD 1) and stderr (FD 2) pass through untouched, so caller-side
|
|
126
|
+
# `>file` and `2>file` redirections on the _spin call behave normally.
|
|
127
|
+
#
|
|
128
|
+
# FD 3 is a TTY (or ROLL_SPIN_FORCE_TTY=1):
|
|
129
|
+
# ⠋ label [Ns] (refreshed ~10/s, line-cleared with \r\033[2K)
|
|
130
|
+
# final: ✓ label (Ns) on success
|
|
131
|
+
# ✗ label (rc=N, Ns) on failure
|
|
132
|
+
#
|
|
133
|
+
# FD 3 not a TTY (CI, pipes, `2>&1 | tee`):
|
|
134
|
+
# » label... on start
|
|
135
|
+
# done label (Ns) on success
|
|
136
|
+
# fail label (rc=N, Ns) on failure
|
|
137
|
+
#
|
|
138
|
+
# Returns wrapped cmd's exit code (transparent under `set -e` callers
|
|
139
|
+
# when used in `if`/`&&`/`||` contexts).
|
|
140
|
+
_spin() {
|
|
141
|
+
local _label="$1"
|
|
142
|
+
shift
|
|
143
|
+
|
|
144
|
+
local _spin_tty=0
|
|
145
|
+
if [ "${ROLL_SPIN_FORCE_TTY:-}" = "1" ] || [ -t 3 ]; then
|
|
146
|
+
_spin_tty=1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
local _spin_start=$SECONDS
|
|
150
|
+
local _spin_pid=""
|
|
151
|
+
|
|
152
|
+
if [ "$_spin_tty" = "1" ]; then
|
|
153
|
+
# Bash 3.2-safe: indexed array of braille frames.
|
|
154
|
+
local _spin_frames
|
|
155
|
+
_spin_frames=( $'\xe2\xa0\x8b' $'\xe2\xa0\x99' $'\xe2\xa0\xb9' $'\xe2\xa0\xb8' $'\xe2\xa0\xbc' $'\xe2\xa0\xb4' $'\xe2\xa0\xa6' $'\xe2\xa0\xa7' $'\xe2\xa0\x87' $'\xe2\xa0\x8f' )
|
|
156
|
+
# Print initial frame at t=0 so users see something immediately.
|
|
157
|
+
printf '\r\033[2K%s %s [0s]' "${_spin_frames[0]}" "$_label" >&3 2>/dev/null || true
|
|
158
|
+
# Only animate when FD 3 is a real TTY — when force-on for tests, skip
|
|
159
|
+
# the background animator so the test gets deterministic output (the
|
|
160
|
+
# initial frame, the cleared final frame).
|
|
161
|
+
if [ -t 3 ]; then
|
|
162
|
+
(
|
|
163
|
+
set +e +u 2>/dev/null
|
|
164
|
+
local _i=1
|
|
165
|
+
local _t0=$_spin_start
|
|
166
|
+
while :; do
|
|
167
|
+
sleep 0.1
|
|
168
|
+
local _e=$(( SECONDS - _t0 ))
|
|
169
|
+
printf '\r\033[2K%s %s [%ds]' "${_spin_frames[$_i]}" "$_label" "$_e" >&3 2>/dev/null || true
|
|
170
|
+
_i=$(( (_i + 1) % 10 ))
|
|
171
|
+
done
|
|
172
|
+
) &
|
|
173
|
+
_spin_pid=$!
|
|
174
|
+
# Kill spinner on Ctrl-C / SIGTERM / EXIT. Save no prior trap because
|
|
175
|
+
# release.sh and its callers install no traps of their own; if a
|
|
176
|
+
# future caller does, _spin's scope is short and traps are restored
|
|
177
|
+
# to default after reaping.
|
|
178
|
+
# shellcheck disable=SC2064
|
|
179
|
+
trap "kill ${_spin_pid} 2>/dev/null; wait ${_spin_pid} 2>/dev/null; trap - INT TERM EXIT; exit 130" INT TERM
|
|
180
|
+
# shellcheck disable=SC2064
|
|
181
|
+
trap "kill ${_spin_pid} 2>/dev/null; wait ${_spin_pid} 2>/dev/null" EXIT
|
|
182
|
+
fi
|
|
183
|
+
else
|
|
184
|
+
printf '» %s...\n' "$_label" >&3 2>/dev/null || true
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
local _spin_rc=0
|
|
188
|
+
if [ "$#" -gt 0 ]; then
|
|
189
|
+
"$@" || _spin_rc=$?
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
if [ -n "$_spin_pid" ]; then
|
|
193
|
+
kill "$_spin_pid" 2>/dev/null || true
|
|
194
|
+
wait "$_spin_pid" 2>/dev/null || true
|
|
195
|
+
trap - INT TERM EXIT
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
local _spin_elapsed=$(( SECONDS - _spin_start ))
|
|
199
|
+
|
|
200
|
+
if [ "$_spin_tty" = "1" ]; then
|
|
201
|
+
if [ "$_spin_rc" -eq 0 ]; then
|
|
202
|
+
printf '\r\033[2K✓ %s (%ds)\n' "$_label" "$_spin_elapsed" >&3 2>/dev/null || true
|
|
203
|
+
else
|
|
204
|
+
printf '\r\033[2K✗ %s (rc=%d, %ds)\n' "$_label" "$_spin_rc" "$_spin_elapsed" >&3 2>/dev/null || true
|
|
205
|
+
fi
|
|
206
|
+
else
|
|
207
|
+
if [ "$_spin_rc" -eq 0 ]; then
|
|
208
|
+
printf 'done %s (%ds)\n' "$_label" "$_spin_elapsed" >&3 2>/dev/null || true
|
|
209
|
+
else
|
|
210
|
+
printf 'fail %s (rc=%d, %ds)\n' "$_label" "$_spin_rc" "$_spin_elapsed" >&3 2>/dev/null || true
|
|
211
|
+
fi
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
return "$_spin_rc"
|
|
215
|
+
}
|
|
216
|
+
|
|
97
217
|
# ─── Helper: read config value ───────────────────────────────────────────────
|
|
98
218
|
config_get() {
|
|
99
219
|
local key="$1"
|
|
@@ -136,7 +256,7 @@ _ensure_config_entries() {
|
|
|
136
256
|
|
|
137
257
|
local -a default_keys=(
|
|
138
258
|
"ai_claude:~/.claude|CLAUDE.md|CLAUDE.md"
|
|
139
|
-
"
|
|
259
|
+
"ai_agy:~/.gemini|GEMINI.md|GEMINI.md"
|
|
140
260
|
"ai_kimi:~/.kimi|AGENTS.md|AGENTS.md"
|
|
141
261
|
"ai_codex:~/.codex|AGENTS.md|AGENTS.md"
|
|
142
262
|
"ai_cursor:~/.cursor|.cursor-rules|.cursor-rules"
|
|
@@ -2495,19 +2615,23 @@ _peer_route() {
|
|
|
2495
2615
|
}
|
|
2496
2616
|
|
|
2497
2617
|
# Open a Terminal.app window attached to the given tmux session (peer
|
|
2498
|
-
# auto-attach). No-ops when muted
|
|
2618
|
+
# auto-attach). No-ops when muted or non-macOS.
|
|
2499
2619
|
# FIX-054: terminal selection removed — always dispatches to macOS
|
|
2500
2620
|
# Terminal.app for predictability (per-user detection silently failed on
|
|
2501
2621
|
# Ghostty upgrades).
|
|
2622
|
+
# Uses `open -g` so the window appears in the background and does not steal
|
|
2623
|
+
# focus from the user's active app (replaces a prior osascript-based
|
|
2624
|
+
# capture-frontmost / restore-focus dance that triggered LaunchServices
|
|
2625
|
+
# "where is <app>" prompts when the active process name differed from its
|
|
2626
|
+
# .app bundle name, e.g. MSTeams vs Microsoft Teams.app).
|
|
2502
2627
|
_peer_auto_attach() {
|
|
2503
2628
|
local session="$1"
|
|
2504
2629
|
[ "$(uname)" = "Darwin" ] || return 0
|
|
2505
2630
|
[ -f "$_LOOP_MUTE_FILE" ] && return 0
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
-e 'delay 0.3' -e 'try' -e 'tell application _prev to activate' -e 'end try' >/dev/null 2>&1 || true
|
|
2631
|
+
local attach_cmd="${_SHARED_ROOT}/loop/attach-${session}.command"
|
|
2632
|
+
printf '#!/bin/bash\nexec tmux attach -t %s\n' "$session" > "$attach_cmd" 2>/dev/null || return 0
|
|
2633
|
+
chmod +x "$attach_cmd" 2>/dev/null || return 0
|
|
2634
|
+
open -g -a Terminal "$attach_cmd" >/dev/null 2>&1 || true
|
|
2511
2635
|
}
|
|
2512
2636
|
|
|
2513
2637
|
# Dispatch a peer CLI command inside an existing tmux session (window 0).
|
|
@@ -2976,10 +3100,13 @@ _agent_argv() {
|
|
|
2976
3100
|
interactive) _AGENT_ARGV=(opencode "$prompt") ;;
|
|
2977
3101
|
*) _AGENT_ARGV=(opencode run "$prompt") ;;
|
|
2978
3102
|
esac ;;
|
|
2979
|
-
|
|
2980
|
-
#
|
|
3103
|
+
agy)
|
|
3104
|
+
# Antigravity (agy) replaces the deprecated Google Gemini CLI as of
|
|
3105
|
+
# late 2025. agy reuses ~/.gemini/ for config and reads GEMINI.md
|
|
3106
|
+
# natively, so the convention sync target is unchanged — only the
|
|
3107
|
+
# invoked binary changes. Interactive-only (used by onboard flow).
|
|
2981
3108
|
case "$mode" in
|
|
2982
|
-
interactive) _AGENT_ARGV=(
|
|
3109
|
+
interactive) _AGENT_ARGV=(agy -i "$prompt") ;;
|
|
2983
3110
|
*) return 1 ;;
|
|
2984
3111
|
esac ;;
|
|
2985
3112
|
*) return 1 ;;
|
|
@@ -3072,7 +3199,7 @@ _slides_lib() {
|
|
|
3072
3199
|
# Returns 0 + prints the path if the template exists, else returns 1.
|
|
3073
3200
|
_slides_template_path() {
|
|
3074
3201
|
local name="$1"
|
|
3075
|
-
local tpl="${ROLL_PKG_DIR}/
|
|
3202
|
+
local tpl="${ROLL_PKG_DIR}/lib/slides/templates/${name}.html"
|
|
3076
3203
|
if [[ -f "$tpl" ]]; then
|
|
3077
3204
|
printf '%s' "$tpl"
|
|
3078
3205
|
return 0
|
|
@@ -3702,8 +3829,12 @@ _slug_migrate_from_legacy() {
|
|
|
3702
3829
|
[[ "$(uname -s 2>/dev/null)" == "Darwin" ]] || return 0
|
|
3703
3830
|
# Compute the pre-FIX-056 slug: same algorithm but without realpath.
|
|
3704
3831
|
local raw_path; raw_path=$(pwd 2>/dev/null)
|
|
3832
|
+
# FIX-094: `_common=$(...)` as a standalone assignment statement inherits the
|
|
3833
|
+
# command's exit code; `set -e` aborts the whole script when cwd is non-git
|
|
3834
|
+
# (git rev-parse exits 128). `|| true` keeps probing semantics — we WANT to
|
|
3835
|
+
# detect "no git" by empty output, not by killing the script.
|
|
3705
3836
|
local _common
|
|
3706
|
-
_common=$(git -C "$raw_path" rev-parse --git-common-dir 2>/dev/null)
|
|
3837
|
+
_common=$(git -C "$raw_path" rev-parse --git-common-dir 2>/dev/null) || true
|
|
3707
3838
|
if [[ -n "$_common" && "$_common" == *"/.git" ]]; then
|
|
3708
3839
|
raw_path="${_common%/.git}"
|
|
3709
3840
|
fi
|
|
@@ -4195,14 +4326,26 @@ _inner_cleanup() {
|
|
|
4195
4326
|
&& [ -n "\${CYCLE_ID:-}" ]; then
|
|
4196
4327
|
_unpushed=\$(cd "\$WT" && git rev-list --count "origin/main..HEAD" 2>/dev/null || echo 0)
|
|
4197
4328
|
if [ "\${_unpushed:-0}" -gt 0 ]; then
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4329
|
+
# FIX-091: prefer a real PR so auto-merge lands the work; tag-only is the
|
|
4330
|
+
# last-resort because it requires manual cherry-pick. Emit cycle_end "done"
|
|
4331
|
+
# (canonical success status the dashboard recognizes) when PR publishes.
|
|
4332
|
+
_slug=""
|
|
4333
|
+
if _gh_resolve _slug \\
|
|
4334
|
+
&& ( cd "\$WT" && _loop_publish_pr "\$BRANCH" "loop cycle \${CYCLE_ID}" ) >/dev/null 2>&1; then
|
|
4335
|
+
_loop_event cycle_end "\${CYCLE_ID}" "\${BRANCH:-}" "done" 2>/dev/null || true
|
|
4203
4336
|
_CYCLE_END_WRITTEN=1
|
|
4204
|
-
_runs_append "
|
|
4205
|
-
_worktree_alert "cycle \${CYCLE_ID}: aborted with \${_unpushed} commits; FIX-
|
|
4337
|
+
_runs_append "done" 0 "[]" 2>/dev/null || true
|
|
4338
|
+
_worktree_alert "cycle \${CYCLE_ID}: aborted with \${_unpushed} commits; FIX-091 published as PR" 2>/dev/null || true
|
|
4339
|
+
else
|
|
4340
|
+
_orphan_tag="loop-orphan-\${CYCLE_ID}"
|
|
4341
|
+
if ( cd "\$WT" && git push origin "\$BRANCH" 2>/dev/null \\
|
|
4342
|
+
&& git tag "\$_orphan_tag" 2>/dev/null \\
|
|
4343
|
+
&& git push origin "\$_orphan_tag" 2>/dev/null ); then
|
|
4344
|
+
_loop_event cycle_end "\${CYCLE_ID}" "\${BRANCH:-}" "orphan" 2>/dev/null || true
|
|
4345
|
+
_CYCLE_END_WRITTEN=1
|
|
4346
|
+
_runs_append "orphan" 0 "[]" 2>/dev/null || true
|
|
4347
|
+
_worktree_alert "cycle \${CYCLE_ID}: aborted with \${_unpushed} commits; FIX-086 pushed orphan tag \${_orphan_tag}" 2>/dev/null || true
|
|
4348
|
+
fi
|
|
4206
4349
|
fi
|
|
4207
4350
|
fi
|
|
4208
4351
|
fi
|
|
@@ -4588,13 +4731,16 @@ if command -v tmux >/dev/null 2>&1; then
|
|
|
4588
4731
|
# to the tmux session so the user can watch the loop work in real time.
|
|
4589
4732
|
# FIX-054: terminal selection removed — fixed to macOS Terminal.app for
|
|
4590
4733
|
# predictability (per-user detection silently failed on Ghostty upgrades).
|
|
4591
|
-
#
|
|
4592
|
-
#
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4734
|
+
# Uses \`open -g\` so the window appears in the background and does not steal
|
|
4735
|
+
# focus. Replaces a prior osascript capture-frontmost / restore-focus dance
|
|
4736
|
+
# that triggered LaunchServices "where is <app>" prompts when the active
|
|
4737
|
+
# process name differed from its .app bundle name (e.g. MSTeams vs
|
|
4738
|
+
# Microsoft Teams.app).
|
|
4739
|
+
if [ -z "\${ROLL_LOOP_NO_POPUP:-}" ] && [ -z "\${BATS_TEST_NUMBER:-}" ] && [ ! -f "\$HOME/.shared/roll/loop/mute-${slug}" ] && [ "\$(uname)" = "Darwin" ]; then
|
|
4740
|
+
_attach_cmd="\$HOME/.shared/roll/loop/attach-\$SESSION.command"
|
|
4741
|
+
printf '#!/bin/bash\\nexec tmux attach -t %s\\n' "\$SESSION" > "\$_attach_cmd" 2>/dev/null || true
|
|
4742
|
+
chmod +x "\$_attach_cmd" 2>/dev/null || true
|
|
4743
|
+
open -g -a Terminal "\$_attach_cmd" >/dev/null 2>&1 || true
|
|
4598
4744
|
fi
|
|
4599
4745
|
_OUTER_TIMEOUT=\$(( \${ROLL_LOOP_CYCLE_TIMEOUT_SEC:-2700} + 300 ))
|
|
4600
4746
|
_outer_wait_start=\$(date +%s)
|
|
@@ -4687,21 +4833,43 @@ _install_launchd_plists() {
|
|
|
4687
4833
|
local after; after=$(cat "$plist")
|
|
4688
4834
|
if [[ "$before" != "$after" ]]; then
|
|
4689
4835
|
updated=$((updated + 1))
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4836
|
+
# FIX-090: gate launchctl writes so a sandboxed plist never gets
|
|
4837
|
+
# registered into the user's REAL gui/<uid> domain. Without this,
|
|
4838
|
+
# `launchctl bootstrap gui/<uid> <sandbox-plist>` outlives TEST_TMP
|
|
4839
|
+
# cleanup as a zombie that either fails silently (EX_CONFIG) or, when
|
|
4840
|
+
# the label collides with the dev's project slug, displaces the real
|
|
4841
|
+
# registration and kills the autonomous loop. Two gate paths:
|
|
4842
|
+
# - explicit: integration_setup exports _LAUNCHD_SKIP_REGISTRY=1
|
|
4843
|
+
# - implicit: if _LAUNCHD_DIR was auto-sandboxed under _SHARED_ROOT
|
|
4844
|
+
# (FIX-087 inner-runner.sh re-source path) we infer skip — callers
|
|
4845
|
+
# that genuinely want the launchctl flow override _LAUNCHD_DIR to
|
|
4846
|
+
# a path outside _SHARED_ROOT (unit tests; production has no
|
|
4847
|
+
# _SHARED_ROOT match against ~/Library/LaunchAgents).
|
|
4848
|
+
# See helpers.bash and tests/unit/launchd_sandbox.bats.
|
|
4849
|
+
local _skip_reg="${_LAUNCHD_SKIP_REGISTRY:-}"
|
|
4850
|
+
if [[ -z "$_skip_reg" ]]; then
|
|
4851
|
+
case "${_LAUNCHD_DIR:-}/" in
|
|
4852
|
+
"${_SHARED_ROOT:-/nonexistent}"/*) _skip_reg=1 ;;
|
|
4853
|
+
*) _skip_reg=0 ;;
|
|
4854
|
+
esac
|
|
4855
|
+
fi
|
|
4856
|
+
if [[ "$_skip_reg" != "1" ]]; then
|
|
4857
|
+
if _launchd_is_loaded "$label"; then
|
|
4858
|
+
# FIX-027: use bootout/bootstrap so we don't disturb the label's
|
|
4859
|
+
# enabled flag in the launchd overrides db (which legacy
|
|
4860
|
+
# unload/load no-`-w` wipes on macOS Sonoma+, causing
|
|
4861
|
+
# `roll loop status` to falsely report off after `roll update`).
|
|
4862
|
+
local uid; uid=$(id -u)
|
|
4863
|
+
launchctl bootout "gui/${uid}/${label}" 2>/dev/null || true
|
|
4864
|
+
launchctl bootstrap "gui/${uid}" "$plist" 2>/dev/null || true
|
|
4865
|
+
elif [[ -z "$before" ]]; then
|
|
4866
|
+
# FIX-059: brand-new plist — macOS FSEvents auto-bootstraps any new
|
|
4867
|
+
# file dropped in ~/Library/LaunchAgents/, so projects never enabled
|
|
4868
|
+
# via 'roll loop on' would fire every hour. Immediately mark disabled
|
|
4869
|
+
# in the overrides db to block that auto-load.
|
|
4870
|
+
local uid; uid=$(id -u)
|
|
4871
|
+
launchctl disable "gui/${uid}/${label}" 2>/dev/null || true
|
|
4872
|
+
fi
|
|
4705
4873
|
fi
|
|
4706
4874
|
fi
|
|
4707
4875
|
done
|
package/conventions/config.yaml
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
sync_claude: ~/.claude/CLAUDE.md
|
|
8
8
|
sync_kimi: ~/.kimi/AGENTS.md
|
|
9
9
|
sync_codex: ~/.codex/AGENTS.md
|
|
10
|
-
|
|
10
|
+
sync_agy: ~/.gemini/GEMINI.md # Antigravity (agy) reuses the legacy ~/.gemini/ path
|
|
11
11
|
|
|
12
12
|
# User preferences
|
|
13
13
|
default_language: zh
|
|
@@ -133,7 +133,7 @@ conventions, deploy targets.
|
|
|
133
133
|
|---|---|---|
|
|
134
134
|
| `conventions/global/AGENTS.md` | `conventions/templates/<type>/AGENTS.md` | All agents |
|
|
135
135
|
| `conventions/global/CLAUDE.md` | `conventions/templates/<type>/CLAUDE.md` | Claude Code |
|
|
136
|
-
| `conventions/global/GEMINI.md` | `conventions/templates/<type>/GEMINI.md` |
|
|
136
|
+
| `conventions/global/GEMINI.md` | `conventions/templates/<type>/GEMINI.md` | Antigravity (agy) — reads `~/.gemini/GEMINI.md` natively |
|
|
137
137
|
| `conventions/global/project_rules.md` | `conventions/templates/<type>/project_rules.md` | Trae IDE |
|
|
138
138
|
|
|
139
139
|
The CLAUDE / GEMINI / project_rules global files themselves declare they
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
# Global Preferences —
|
|
1
|
+
# Global Preferences — Antigravity (agy)
|
|
2
2
|
|
|
3
3
|
> Extends AGENTS.md in this directory — read that first for shared conventions.
|
|
4
|
-
> This file adds
|
|
4
|
+
> This file adds Antigravity-specific configuration only.
|
|
5
|
+
>
|
|
6
|
+
> File is named `GEMINI.md` because agy reads `~/.gemini/GEMINI.md` natively
|
|
7
|
+
> (it reuses the legacy Gemini CLI config dir). The filename is the canonical
|
|
8
|
+
> agy-side filename; the content here is for agy.
|
|
5
9
|
|
|
6
|
-
##
|
|
10
|
+
## Antigravity-Specific
|
|
7
11
|
|
|
8
12
|
- When running shell commands, prefer the most specific tool available.
|
|
9
13
|
- When a project has Roll workflow, follow the AGENTS.md conventions and use Roll skills.
|
|
14
|
+
- Invoke interactively with `agy -i "<prompt>"`; non-interactive with `agy -p "<prompt>"`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Project Preferences — Backend Service (
|
|
1
|
+
# Project Preferences — Backend Service (Antigravity)
|
|
2
2
|
|
|
3
|
-
> Extends global GEMINI.md + project AGENTS.md.
|
|
3
|
+
> Extends global GEMINI.md (Antigravity) + project AGENTS.md.
|
|
4
4
|
|
|
5
5
|
## Stack
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- Database: Prisma or Drizzle ORM
|
|
9
9
|
- Testing: Vitest + Supertest
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Antigravity (agy) Notes
|
|
12
12
|
|
|
13
13
|
- No frontend in this project. API-only service.
|
|
14
14
|
- Write integration tests that hit real endpoints, not mocked handlers.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Project Preferences — CLI Tool (
|
|
1
|
+
# Project Preferences — CLI Tool (Antigravity)
|
|
2
2
|
|
|
3
|
-
> Extends global GEMINI.md + project AGENTS.md.
|
|
3
|
+
> Extends global GEMINI.md (Antigravity) + project AGENTS.md.
|
|
4
4
|
|
|
5
5
|
## Stack
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- CLI framework: commander or citty
|
|
9
9
|
- Testing: Vitest
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Antigravity (agy) Notes
|
|
12
12
|
|
|
13
13
|
- No server, no frontend. CLI tool only.
|
|
14
14
|
- Test commands by running them, not just unit tests.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
# Project Preferences — Frontend Only (
|
|
1
|
+
# Project Preferences — Frontend Only (Antigravity)
|
|
2
2
|
|
|
3
|
-
> Extends global GEMINI.md + project AGENTS.md.
|
|
3
|
+
> Extends global GEMINI.md (Antigravity) + project AGENTS.md.
|
|
4
4
|
|
|
5
5
|
## Stack
|
|
6
6
|
|
|
7
7
|
- React + shadcn/ui + Tailwind CSS + Vite
|
|
8
8
|
- Testing: Vitest + Playwright
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Antigravity (agy) Notes
|
|
11
11
|
|
|
12
12
|
- No backend in this project. All data via external API consumption.
|
|
13
13
|
- Run `npm run build` to verify production bundle compiles before pushing.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Project Preferences — Fullstack Web (
|
|
1
|
+
# Project Preferences — Fullstack Web (Antigravity)
|
|
2
2
|
|
|
3
|
-
> Extends global GEMINI.md + project AGENTS.md.
|
|
3
|
+
> Extends global GEMINI.md (Antigravity) + project AGENTS.md.
|
|
4
4
|
|
|
5
5
|
## Stack
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- Backend: Node.js API (Express/Hono/Fastify)
|
|
9
9
|
- Testing: Vitest (unit) + Playwright (E2E)
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Antigravity (agy) Notes
|
|
12
12
|
|
|
13
13
|
- When modifying API contracts, update both `api/types.ts` and `src/shared/types/` in the same commit.
|
|
14
14
|
- Run `npm run build` to verify both frontend and backend compile before pushing.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/model_prices.py
CHANGED
|
@@ -12,15 +12,26 @@ to sonnet rates with a stderr warning so dashboards don't blank out.
|
|
|
12
12
|
import sys
|
|
13
13
|
from typing import Dict, Optional
|
|
14
14
|
|
|
15
|
-
# Rates per million tokens (USD).
|
|
15
|
+
# Rates per million tokens (USD). cache_create = 5-minute cache write (1.25x
|
|
16
|
+
# input). 1-hour cache writes (2x input) are not modeled — Roll loop uses the
|
|
17
|
+
# default 5m caching only.
|
|
18
|
+
# Source: https://platform.claude.com/docs/en/about-claude/pricing
|
|
16
19
|
PRICES: Dict[str, Dict[str, float]] = {
|
|
17
|
-
# Claude 4.x family
|
|
18
|
-
|
|
19
|
-
"claude-opus-4-
|
|
20
|
+
# Claude 4.x Opus family — 2026-05 repricing: Opus 4.5+ moved to
|
|
21
|
+
# $5/$25 base, 3x cheaper than Opus 4 / 4.1.
|
|
22
|
+
"claude-opus-4-7": {"in": 5.00, "out": 25.00, "cache_create": 6.25, "cache_read": 0.50},
|
|
23
|
+
"claude-opus-4-6": {"in": 5.00, "out": 25.00, "cache_create": 6.25, "cache_read": 0.50},
|
|
24
|
+
"claude-opus-4-5": {"in": 5.00, "out": 25.00, "cache_create": 6.25, "cache_read": 0.50},
|
|
25
|
+
"claude-opus-4-1": {"in": 15.00, "out": 75.00, "cache_create": 18.75, "cache_read": 1.50},
|
|
26
|
+
"claude-opus-4": {"in": 15.00, "out": 75.00, "cache_create": 18.75, "cache_read": 1.50},
|
|
27
|
+
# Claude 4.x Sonnet family.
|
|
20
28
|
"claude-sonnet-4-6": {"in": 3.00, "out": 15.00, "cache_create": 3.75, "cache_read": 0.30},
|
|
29
|
+
"claude-sonnet-4-5": {"in": 3.00, "out": 15.00, "cache_create": 3.75, "cache_read": 0.30},
|
|
21
30
|
"claude-sonnet-4": {"in": 3.00, "out": 15.00, "cache_create": 3.75, "cache_read": 0.30},
|
|
31
|
+
# Claude 4.x Haiku family.
|
|
22
32
|
"claude-haiku-4-5": {"in": 1.00, "out": 5.00, "cache_create": 1.25, "cache_read": 0.10},
|
|
23
|
-
# Older
|
|
33
|
+
# Older / retired models (Bedrock & Vertex only for 3.5 Haiku).
|
|
34
|
+
"claude-haiku-3-5": {"in": 0.80, "out": 4.00, "cache_create": 1.00, "cache_read": 0.08},
|
|
24
35
|
"claude-3-5-sonnet": {"in": 3.00, "out": 15.00, "cache_create": 3.75, "cache_read": 0.30},
|
|
25
36
|
}
|
|
26
37
|
|