@routerhub/agent-rules 1.5.197 → 1.5.199

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/AGENTS.base.md CHANGED
@@ -695,6 +695,32 @@ agent-rules 生成的规则文件分两层,行为与归属不同,评审/发
695
695
  4. 一旦 `eval` / `snapshot` 返回的内容不是自己操作的页面(URL/内容不符),
696
696
  **第一反应是标签页被抢占**:切回自己的 tab id 后重试,禁止盲目重试同一条命令。
697
697
 
698
+ ## 🚨 agent-browser 内存收尾铁律(用完必须收摊)
699
+
700
+ **根因**:agent-browser CLI 本体很轻,但它背后复用的 Chrome Profile 会保留标签页、
701
+ Service Worker、登录态缓存和页面运行时。每次任务只打开不关闭,`9223` / `9226` 的
702
+ Chrome Helper 会越积越多,表现为“agent-browser 用着用着越来越卡”。
703
+
704
+ **必须遵守**:
705
+
706
+ 1. 每次 `agent-browser tab new` 后必须记录本次任务创建的 tab id;任务结束前,必须关闭
707
+ 本任务打开的所有 tab,禁止把 Cloud Console、GitHub、Slack、Google 登录页等任务页面
708
+ 长期留在 agent-browser Chrome 里。
709
+ 2. 每次浏览器自动化任务结束前,**执行任务的 Agent 必须自动运行** `agent-browser-cleanup auto`
710
+ (或仓库源码内 `bash scripts/agent-browser-cleanup.sh auto`),禁止把这一步交给用户手动判断。
711
+ 用户只负责提出任务,Agent 负责判断是否该释放内存。
712
+ 3. `9226` 无头 Chrome 优先用于 agent 自动化;`agent-browser-cleanup auto` 会在 `9226` 的 tab 数
713
+ > 10,或 RSS > 1500MB 时自动释放它。释放后下次需要浏览器时再重新启动,不要为了“可能等会用”
714
+ 长期占着内存。
715
+ 4. `9223` 有头 Chrome 只在需要用户手动登录、手动查看动态效果、或必须共享可见页面时启动;
716
+ 任务结束且用户不再需要查看时,必须关闭本任务 tab;`auto` 默认不会关闭 `9223`,避免误关用户
717
+ 正在看的页面。只有明确确认 `9223` 没有人工操作中的页面时,才允许设置
718
+ `AGENT_BROWSER_CLEANUP_INCLUDE_HEADED=1 agent-browser-cleanup auto` 或执行 `agent-browser-cleanup hard`。
719
+ 5. 禁止长期同时保留 `9223` + `9226` 两套 agent-browser Chrome 实例,除非当前任务明确需要。
720
+ 多会话并行时也必须各自用 namespace 隔离,任务完成各自清理自己创建的 tab。
721
+ 6. 禁止用 `kill -9` / `pkill -9` 强杀 Chrome;清理只能使用 `agent-browser-cleanup`、
722
+ `chrome-bridge headless-stop`,或 `/bin/kill -TERM` 这类可让 Chrome 正常退出的方式。
723
+
698
724
  ## 优先级
699
725
 
700
726
  1. 项目私有规则(AGENTS.private.md)
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  所有对 @routerhub/agent-rules 的重大更改都会记录在这个文件中。
4
4
 
5
+ ## [1.5.199] - 2026-09-08
6
+
7
+ ### Changed
8
+
9
+ - **agent-browser 收尾从“手动命令”升级为“Agent 自动判断”**:规则明确要求每次浏览器自动化任务结束前,由执行任务的 Agent 自动运行 `agent-browser-cleanup auto`,禁止把判断交给用户。`auto` 模式同步调整为默认只自动释放超阈值的 `9226` 无头 Chrome;`9223` 有头 Chrome 默认只提示,需设置 `AGENT_BROWSER_CLEANUP_INCLUDE_HEADED=1` 才会自动关闭,避免误关用户正在看的页面。
10
+
11
+ ## [1.5.198] - 2026-09-08
12
+
13
+ ### Added
14
+
15
+ - **新增「agent-browser 内存收尾铁律」与 `agent-browser-cleanup` 命令**:要求每次 browser 自动化任务结束关闭本任务 tab,并检查 `9223` / `9226` 的 tab 数与 RSS;`9226` 超过 10 个 tab 或 1500MB 时必须释放,避免 Chrome Profile 长期堆积导致 agent-browser 越用越卡。新增 `scripts/agent-browser-cleanup.sh`,支持 `status` / `soft` / `auto` / `hard` 四种模式,默认只读状态,释放时使用正常退出方式,禁止 `kill -9` 强杀 Chrome。
16
+
5
17
  ## [1.5.164] - 2026-08-31
6
18
 
7
19
  ### Changed
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "@routerhub/agent-rules",
3
- "version": "1.5.197",
3
+ "version": "1.5.199",
4
4
  "description": "Shared Copilot agent rules and guidelines for RouterHub projects",
5
5
  "main": "AGENTS.base.md",
6
6
  "bin": {
7
- "agent-rules": "merge.js"
7
+ "agent-rules": "merge.js",
8
+ "agent-browser-cleanup": "scripts/agent-browser-cleanup.sh"
8
9
  },
9
10
  "files": [
10
11
  "AGENTS.base.md",
11
12
  "rules/",
12
13
  "skills/",
14
+ "scripts/agent-browser-cleanup.sh",
13
15
  "merge.js",
14
16
  "AGENTS.private.example.md",
15
17
  "PULL_REQUEST_TEMPLATE.md",
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ MODE="${1:-status}"
5
+ TAB_LIMIT="${AGENT_BROWSER_TAB_LIMIT:-10}"
6
+ RSS_LIMIT_MB="${AGENT_BROWSER_RSS_LIMIT_MB:-1500}"
7
+ INCLUDE_HEADED="${AGENT_BROWSER_CLEANUP_INCLUDE_HEADED:-0}"
8
+
9
+ profileForPort() {
10
+ case "$1" in
11
+ 9223) printf '%s\n' "$HOME/.agent-browser-profile" ;;
12
+ 9226) printf '%s\n' "$HOME/.agent-browser-profile-headless" ;;
13
+ *) printf '' ;;
14
+ esac
15
+ }
16
+
17
+ usage() {
18
+ cat <<'USAGE'
19
+ Usage: scripts/agent-browser-cleanup.sh [status|soft|hard|auto]
20
+
21
+ Modes:
22
+ status 只查看 9223/9226 的标签页数量与内存占用
23
+ soft 关闭 about:blank、newtab、devtools 等无业务标签页
24
+ hard 优雅退出 agent-browser 专用 Chrome(9223/9226),释放内存
25
+ auto 超阈值时自动释放 9226;9223 默认只提示,避免误关用户正在看的页面
26
+
27
+ Env:
28
+ AGENT_BROWSER_TAB_LIMIT 默认 10
29
+ AGENT_BROWSER_RSS_LIMIT_MB 默认 1500
30
+ AGENT_BROWSER_CLEANUP_INCLUDE_HEADED=1 时,auto 也允许释放 9223
31
+ USAGE
32
+ }
33
+
34
+ if [[ "$MODE" == "-h" || "$MODE" == "--help" ]]; then
35
+ usage
36
+ exit 0
37
+ fi
38
+
39
+ if [[ "$MODE" != "status" && "$MODE" != "soft" && "$MODE" != "hard" && "$MODE" != "auto" ]]; then
40
+ usage >&2
41
+ exit 2
42
+ fi
43
+
44
+ portStatus() {
45
+ local portNumber="$1"
46
+ local profileDir=""
47
+ local tabCount="0"
48
+ local rssMb="0"
49
+ local profileArg=""
50
+
51
+ profileDir=$(profileForPort "$portNumber")
52
+ profileArg="--user-data-dir=${profileDir}"
53
+ rssMb=$(ps -axo rss=,command= | awk -v profileArg="$profileArg" '
54
+ {
55
+ for (fieldIndex = 2; fieldIndex <= NF; fieldIndex++) {
56
+ if ($fieldIndex == profileArg) {
57
+ sum += $1
58
+ break
59
+ }
60
+ }
61
+ }
62
+ END {printf "%d", sum / 1024}
63
+ ')
64
+
65
+ if curl -sf "http://127.0.0.1:${portNumber}/json/list" >/tmp/agent-browser-tabs-${portNumber}.json 2>/dev/null; then
66
+ tabCount=$(jq 'length' "/tmp/agent-browser-tabs-${portNumber}.json" 2>/dev/null || echo "0")
67
+ fi
68
+
69
+ rm -f "/tmp/agent-browser-tabs-${portNumber}.json"
70
+ printf '%s %s %s\n' "$portNumber" "$tabCount" "$rssMb"
71
+ }
72
+
73
+ printStatus() {
74
+ printf 'port\ttabs\trssMB\n'
75
+ portStatus 9223 | awk '{printf "%s\t%s\t%s\n", $1, $2, $3}'
76
+ portStatus 9226 | awk '{printf "%s\t%s\t%s\n", $1, $2, $3}'
77
+ }
78
+
79
+ closeChromeByPort() {
80
+ local portNumber="$1"
81
+ local profileDir=""
82
+ local profileArg=""
83
+ local processIds=""
84
+ profileDir=$(profileForPort "$portNumber")
85
+ profileArg="--user-data-dir=${profileDir}"
86
+ processIds=$(ps -axo pid=,command= | awk -v profileArg="$profileArg" '
87
+ {
88
+ hasProfile = 0
89
+ for (fieldIndex = 2; fieldIndex <= NF; fieldIndex++) {
90
+ if ($fieldIndex == profileArg) hasProfile = 1
91
+ }
92
+ if (hasProfile) print $1
93
+ }
94
+ ')
95
+ if [[ -z "$processIds" ]]; then
96
+ echo "port ${portNumber}: no agent-browser Chrome process"
97
+ return
98
+ fi
99
+
100
+ echo "port ${portNumber}: graceful quit"
101
+ printf '%s\n' "$processIds" | xargs -n1 /bin/kill -TERM
102
+ }
103
+
104
+ softCleanup() {
105
+ local portNumber="$1"
106
+ if ! curl -sf "http://127.0.0.1:${portNumber}/json/list" >/tmp/agent-browser-tabs-${portNumber}.json 2>/dev/null; then
107
+ echo "port ${portNumber}: not reachable"
108
+ return
109
+ fi
110
+
111
+ jq -r '.[] | select(.url | test("^(about:blank|chrome://newtab|devtools://|chrome://)")).id' "/tmp/agent-browser-tabs-${portNumber}.json" |
112
+ while IFS= read -r tabId; do
113
+ [[ -z "$tabId" ]] && continue
114
+ curl -sf "http://127.0.0.1:${portNumber}/json/close/${tabId}" >/dev/null || true
115
+ echo "port ${portNumber}: closed idle tab ${tabId}"
116
+ done
117
+
118
+ rm -f "/tmp/agent-browser-tabs-${portNumber}.json"
119
+ }
120
+
121
+ autoCleanup() {
122
+ while read -r portNumber tabCount rssMb; do
123
+ if (( tabCount <= TAB_LIMIT && rssMb <= RSS_LIMIT_MB )); then
124
+ continue
125
+ fi
126
+
127
+ echo "port ${portNumber}: over limit tabs=${tabCount}/${TAB_LIMIT} rssMB=${rssMb}/${RSS_LIMIT_MB}"
128
+ if [[ "$portNumber" == "9226" ]]; then
129
+ closeChromeByPort "$portNumber"
130
+ continue
131
+ fi
132
+
133
+ if [[ "$portNumber" == "9223" && "$INCLUDE_HEADED" == "1" ]]; then
134
+ closeChromeByPort "$portNumber"
135
+ continue
136
+ fi
137
+
138
+ echo "port ${portNumber}: headed Chrome skipped; set AGENT_BROWSER_CLEANUP_INCLUDE_HEADED=1 to close it automatically"
139
+ done < <(portStatus 9223 && portStatus 9226)
140
+ }
141
+
142
+ case "$MODE" in
143
+ status)
144
+ printStatus
145
+ ;;
146
+ soft)
147
+ softCleanup 9223
148
+ softCleanup 9226
149
+ printStatus
150
+ ;;
151
+ hard)
152
+ closeChromeByPort 9223
153
+ closeChromeByPort 9226
154
+ ;;
155
+ auto)
156
+ printStatus
157
+ autoCleanup
158
+ ;;
159
+ esac