npx skills add https://github.com/garrytan/gstack --skill gstack_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
_CONTRIB=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true)
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
mkdir -p ~/.gstack/analytics
echo '{"skill":"gstack","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
如果 PROACTIVE 是 "false",不要主动建议 gstack 技能——仅在用户明确要求时调用它们。用户已选择退出主动建议。
如果输出显示 UPGRADE_AVAILABLE <old> <new>:读取 ~/.claude/skills/gstack/gstack-upgrade/SKILL.md 并遵循“内联升级流程”(如果已配置则自动升级,否则使用 4 个选项询问用户,如果拒绝则写入暂停状态)。如果显示 JUST_UPGRADED <from> <to>:告诉用户“正在运行 gstack v{to}(刚刚更新!)”并继续。
如果 LAKE_INTRO 是 no:在继续之前,介绍完整性原则。告诉用户:“gstack 遵循 煮沸湖水 原则——当 AI 使边际成本接近于零时,总是做完整的事情。了解更多:https://garryslist.org/posts/boil-the-ocean” 然后提议在他们的默认浏览器中打开这篇文章:
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
只有在用户同意时才运行 open。始终运行 touch 以标记为已读。这只发生一次。
如果 TEL_PROMPTED 是 no 并且 LAKE_INTRO 是 yes:在处理完湖水介绍后,询问用户关于遥测的事宜。使用 AskUserQuestion:
帮助 gstack 变得更好!社区模式共享使用数据(您使用哪些技能、花费多长时间、崩溃信息)以及一个稳定的设备 ID,以便我们能够跟踪趋势并更快地修复错误。从不发送代码、文件路径或仓库名称。随时可以通过
gstack-config set telemetry off更改。
选项:
如果选择 A:运行 ~/.claude/skills/gstack/bin/gstack-config set telemetry community
如果选择 B:询问一个后续的 AskUserQuestion:
匿名模式怎么样?我们只了解到 有人 使用了 gstack——没有唯一 ID,无法连接会话。只是一个帮助我们了解是否有人在使用的计数器。
选项:
如果 B→A:运行 ~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous 如果 B→B:运行 ~/.claude/skills/gstack/bin/gstack-config set telemetry off
始终运行:
touch ~/.gstack/.telemetry-prompted
这只发生一次。如果 TEL_PROMPTED 是 yes,则完全跳过此步骤。
每次调用 AskUserQuestion 时,务必遵循此结构:
_BRANCH 值——不要使用对话历史或 gitStatus 中的任何分支)以及当前计划/任务。(1-2 句话)RECOMMENDATION: 选择 [X] 因为 [一行原因]——始终倾向于完整选项而非快捷方式(参见完整性原则)。为每个选项包含 Completeness: X/10。校准:10 = 完整实现(所有边界情况,全覆盖),7 = 覆盖主要路径但跳过一些边界情况,3 = 推迟大量工作的快捷方式。如果两个选项都是 8+,选择更高的;如果有一个 ≤5,标记出来。A) ... B) ... C) ...——当某个选项涉及工作量时,显示两个尺度:(人工: ~X / CC: ~Y)假设用户已经 20 分钟没有看这个窗口,并且没有打开代码。如果你需要阅读源代码才能理解你自己的解释,那就太复杂了。
每个技能的说明可能会在此基线之上添加额外的格式规则。
AI 辅助编码使完整性的边际成本接近于零。当你呈现选项时:
| 任务类型 | 人工团队 | CC+gstack | 压缩比 |
|---|---|---|---|
| 样板代码 / 脚手架 | 2 天 | 15 分钟 | ~100x |
| 测试编写 | 1 天 | 15 分钟 | ~50x |
| 功能实现 | 1 周 | 30 分钟 | ~30x |
| Bug 修复 + 回归测试 | 4 小时 | 15 分钟 | ~20x |
| 架构 / 设计 | 2 天 | 4 小时 | ~5x |
| 研究 / 探索 | 1 天 | 3 小时 | ~3x |
反模式——不要这样做:
前言中的 REPO_MODE 告诉你谁拥有此仓库中的问题:
solo —— 一个人完成 80%+ 的工作。他们负责一切。当你注意到当前分支变更之外的问题(测试失败、弃用警告、安全建议、linting 错误、死代码、环境问题)时,主动调查并提供修复。唯一的开发者是唯一会修复它的人。默认采取行动。collaborative —— 多个活跃贡献者。当你注意到分支变更之外的问题时,通过 AskUserQuestion 标记它们——这可能是其他人的责任。默认询问,而非修复。unknown —— 视为协作模式(更安全的默认值——修复前先询问)。发现问题,及时报告: 在任何工作流程步骤中,每当你注意到看起来不对劲的地方——不仅仅是测试失败——都要简要标记出来。一句话:你注意到了什么及其影响。在 solo 模式下,接着问“需要我修复它吗?”在协作模式下,只需标记并继续。
绝不要让注意到的问题悄无声息地过去。主动沟通是核心。
在构建基础设施、不熟悉的模式或任何运行时可能内置的功能之前——先搜索。 阅读 ~/.claude/skills/gstack/ETHOS.md 了解完整理念。
三层知识:
顿悟时刻: 当第一性原理推理揭示传统智慧是错误的时候,为其命名:“EUREKA:每个人都做 X 是因为 [假设]。但 [证据] 表明这是错误的。Y 更好是因为 [推理]。”
记录顿悟时刻:
jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg skill "SKILL_NAME" --arg branch "$(git branch --show-current 2>/dev/null)" --arg insight "ONE_LINE_SUMMARY" '{ts:$ts,skill:$skill,branch:$branch,insight:$insight}' >> ~/.gstack/analytics/eureka.jsonl 2>/dev/null || true
替换 SKILL_NAME 和 ONE_LINE_SUMMARY。内联运行——不要中断工作流程。
WebSearch 后备方案: 如果 WebSearch 不可用,跳过搜索步骤并注明:“搜索不可用——仅使用发行版内的知识进行。”
如果 _CONTRIB 是 true:你处于贡献者模式。你是一个同时帮助改进 gstack 的用户。
在每个主要工作流程步骤结束时(不是每个命令之后),反思你使用的 gstack 工具。给你的体验打分,0 到 10 分。如果不是 10 分,思考原因。如果存在明显的、可操作的 bug 或者 gstack 代码或技能 markdown 本可以做得更好的、有洞察力的、有趣的事情——提交一份现场报告。也许我们的贡献者会帮助我们变得更好!
校准——这是标准: 例如,$B js "await fetch(...)" 曾经因为 gstack 没有在异步上下文中包装表达式而失败,错误为 SyntaxError: await is only valid in async functions。问题虽小,但输入是合理的,gstack 本应处理它——这就是值得提交的那种事情。比这更不重要的事情,忽略。
不值得提交: 用户的应用 bug、到用户 URL 的网络错误、用户站点的身份验证失败、用户自己的 JS 逻辑 bug。
提交方式: 使用以下所有部分编写 ~/.gstack/contributor-logs/{slug}.md(不要截断——包含从日期/版本页脚之前的所有部分):
# {标题}
嘿 gstack 团队——在使用 /{技能名称} 时遇到了这个:
**我想做什么:** {用户/代理试图做什么}
**实际发生了什么:** {实际发生了什么}
**我的评分:** {0-10} —— {一句话说明为什么不是 10 分}
## 重现步骤
1. {步骤}
## 原始输出
{在此处粘贴实际的错误或意外输出}
## 如何能达到 10 分
{一句话:gstack 本应如何不同地处理}
**日期:** {YYYY-MM-DD} | **版本:** {gstack 版本} | **技能:** /{技能}
Slug:小写,连字符,最多 60 个字符(例如 browse-js-no-await)。如果文件已存在则跳过。每个会话最多 3 份报告。内联提交并继续——不要中断工作流程。告诉用户:“已提交 gstack 现场报告:{标题}”
完成技能工作流程时,使用以下之一报告状态:
随时可以停下来并说“这对我来说太难了”或“我对这个结果没有信心。”
糟糕的工作比没有工作更糟。你不会因为升级而受到惩罚。
升级格式:
STATUS: BLOCKED | NEEDS_CONTEXT
REASON: [1-2 句话]
ATTEMPTED: [你尝试了什么]
RECOMMENDATION: [用户下一步应该做什么]
技能工作流程完成(成功、错误或中止)后,记录遥测事件。从此文件的 YAML 前言中的 name: 字段确定技能名称。根据工作流程结果确定结果(正常完成则为成功,失败则为错误,用户中断则为中止)。
计划模式例外——始终运行: 此命令将遥测写入 ~/.gstack/analytics/(用户配置目录,非项目文件)。技能前言已经写入同一目录——这是相同的模式。跳过此命令会丢失会话持续时间和结果数据。
运行此 bash:
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
~/.claude/skills/gstack/bin/gstack-telemetry-log \
--skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
将 SKILL_NAME 替换为前言中的实际技能名称,OUTCOME 替换为 success/error/abort,USED_BROWSE 替换为 true/false(基于是否使用了 $B)。如果无法确定结果,使用 "unknown"。这在后台运行,永远不会阻塞用户。
当你处于计划模式并即将调用 ExitPlanMode 时:
## GSTACK REVIEW REPORT 部分。bash ~/.claude/skills/gstack/bin/gstack-review-read
然后将 ## GSTACK REVIEW REPORT 部分写入计划文件末尾:
---CONFIG--- 之前的 JSONL 行):使用标准报告表格格式化,包含每个技能的运行/状态/发现,格式与审查技能使用的相同。NO_REVIEWS 或为空:写入此占位表格:
## GSTACK REVIEW REPORT
审查 | 触发 | 原因 | 运行次数 | 状态 | 发现
---|---|---|---|---|---
CEO 审查 | `/plan-ceo-review` | 范围与策略 | 0 | — | —
Codex 审查 | `/codex review` | 独立的第二意见 | 0 | — | —
工程审查 | `/plan-eng-review` | 架构与测试(必需) | 0 | — | —
设计审查 | `/plan-design-review` | UI/UX 差距 | 0 | — | —
**裁决:** 尚无审查——运行 `/autoplan` 获取完整审查流水线,或运行上述单个审查。 ```
**计划模式例外——始终运行:** 这写入计划文件,这是你在计划模式下唯一允许编辑的文件。计划文件审查报告是计划动态状态的一部分。
如果 `PROACTIVE` 是 `false`:在此会话期间**不要**主动建议其他 gstack 技能。仅运行用户明确调用的技能。此偏好通过 `gstack-config` 在会话间持续存在。
# gstack browse:QA 测试与自食其果
持久化的无头 Chromium。首次调用自动启动(约 3 秒),然后每次命令约 100-200 毫秒。空闲 30 分钟后自动关闭。状态在调用间保持(cookies、标签页、会话)。
## 设置(在任何浏览命令之前运行此检查)
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
B=""
[ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && B="$_ROOT/.claude/skills/gstack/browse/dist/browse"
[ -z "$B" ] && B=~/.claude/skills/gstack/browse/dist/browse
if [ -x "$B" ]; then
echo "READY: $B"
else
echo "NEEDS_SETUP"
fi
如果显示 `NEEDS_SETUP`:
1. 告诉用户:“gstack browse 需要一次性构建(约 10 秒)。可以继续吗?”然后**停止**并等待。
2. 运行:`cd <SKILL_DIR> && ./setup`
3. 如果 `bun` 未安装:`curl -fsSL https://bun.sh/install | bash`
## 重要事项
* 通过 Bash 使用编译后的二进制文件:`$B <命令>`
* **绝不**使用 `mcp__claude-in-chrome__*` 工具。它们速度慢且不可靠。
* 浏览器在调用间保持——cookies、登录会话和标签页会保留。
* 对话框(alert/confirm/prompt)默认自动接受——浏览器不会卡住。
* **显示截图:** 在 `$B screenshot`、`$B snapshot -a -o` 或 `$B responsive` 之后,始终对输出的 PNG 文件使用 Read 工具,以便用户能看到它们。没有这一步,截图是不可见的。
## QA 工作流程
### 测试用户流程(登录、注册、结账等)
# 1. 转到页面
$B goto https://app.example.com/login
# 2. 查看哪些是可交互的
$B snapshot -i
# 3. 使用引用填写表单
$B fill @e3 "test@example.com"
$B fill @e4 "password123"
$B click @e5
# 4. 验证是否成功
$B snapshot -D # diff 显示点击后的变化
$B is visible ".dashboard" # 断言仪表板出现
$B screenshot /tmp/after-login.png
### 验证部署 / 检查生产环境
$B goto https://yourapp.com
$B text # 读取页面——加载了吗?
$B console # 有 JS 错误吗?
$B network # 有失败的请求吗?
$B js "document.title" # 标题正确吗?
$B is visible ".hero-section" # 关键元素存在吗?
$B screenshot /tmp/prod-check.png
### 自食其果:端到端测试功能
# 导航到功能
$B goto https://app.example.com/new-feature
# 拍摄带注释的截图——显示每个带标签的可交互元素
$B snapshot -i -a -o /tmp/feature-annotated.png
# 查找所有可点击的东西(包括 cursor:pointer 的 div)
$B snapshot -C
# 逐步执行流程
$B snapshot -i # 基线
$B click @e3 # 交互
$B snapshot -D # 发生了什么变化?(统一 diff)
# 检查元素状态
$B is visible ".success-toast"
$B is enabled "#next-step-btn"
$B is checked "#agree-checkbox"
# 交互后检查控制台是否有错误
$B console
### 测试响应式布局
# 快速:在移动端/平板/桌面端拍摄 3 张截图
$B goto https://yourapp.com
$B responsive /tmp/layout
# 手动:特定视口
$B viewport 375x812 # iPhone
$B screenshot /tmp/mobile.png
$B viewport 1440x900 # 桌面
$B screenshot /tmp/desktop.png
# 元素截图(裁剪到特定元素)
$B screenshot "#hero-banner" /tmp/hero.png
$B snapshot -i
$B screenshot @e3 /tmp/button.png
# 区域裁剪
$B screenshot --clip 0,0,800,600 /tmp/above-fold.png
# 仅视口(无滚动)
$B screenshot --viewport /tmp/viewport.png
### 测试文件上传
$B goto https://app.example.com/upload
$B snapshot -i
$B upload @e3 /path/to/test-file.pdf
$B is visible ".upload-success"
$B screenshot /tmp/upload-result.png
### 测试带验证的表单
$B goto https://app.example.com/form
$B snapshot -i
# 提交空表单——检查验证错误是否出现
$B click @e10 # 提交按钮
$B snapshot -D # diff 显示错误消息出现
$B is visible ".error-message"
# 填写并重新提交
$B fill @e3 "valid input"
$B click @e10
$B snapshot -D # diff 显示错误消失,成功状态
### 测试对话框(删除确认、提示框)
# 在触发之前设置对话框处理
$B dialog-accept # 将自动接受下一个 alert/confirm
$B click "#delete-button" # 触发确认对话框
$B dialog # 查看出现了什么对话框
$B snapshot -D # 验证项目是否被删除
# 对于需要输入的提示框
$B dialog-accept "my answer" # 带文本接受
$B click "#rename-button" # 触发提示框
### 测试需要身份验证的页面(导入真实浏览器 cookies)
# 从你的真实浏览器导入 cookies(打开交互式选择器)
$B cookie-import-browser
# 或者直接导入特定域
$B cookie-import-browser comet --domain .github.com
# 现在测试需要身份验证的页面
$B goto https://github.com/settings/profile
$B snapshot -i
$B screenshot /tmp/github-profile.png
### 比较两个页面 / 环境
$B diff https://staging.app.com https://prod.app.com
### 多步骤链(适用于长流程的高效方式)
echo '[
["goto","https://app.example.com"],
["snapshot","-i"],
["fill","@e3","test@test.com"],
["fill","@e4","password"],
["click","@e5"],
["snapshot","-D"],
["screenshot","/tmp/result.png"]
]' | $B chain
## 快速断言模式
# 元素存在且可见
$B is visible ".modal"
# 按钮启用/禁用
$B is enabled "#submit-btn"
$B is disabled "#submit-btn"
# 复选框状态
$B is checked "#agree"
# 输入框可编辑
$B is editable "#name-field"
# 元素获得焦点
$B is focused "#search-input"
# 页面包含文本
$B js "document.body.textContent.includes('Success')"
# 元素数量
$B js "document.querySelectorAll('.list-item').length"
# 特定属性值
$B attrs "#logo" # 以 JSON 返回所有属性
# CSS 属性
$B css ".button" "background-color"
## 快照系统
快照是你理解和与页面交互的主要工具。
-i --interactive 仅可交互元素(按钮、链接、输入框)并带有 @e 引用
-c --compact 紧凑(无空结构节点)
-d <N> --depth 限制树深度(0 = 仅根节点,默认:无限制)
-s <sel> --selector 限定到 CSS 选择器
-D --diff 与先前快照的统一 diff(首次调用存储基线)
-a --annotate 带红色覆盖框和引用标签的注释截图
-o <path> --output 注释截图的输出路径(默认:<temp>/browse-annotated.png)
-C --cursor-interactive 光标可交互元素(@c 引用——带 pointer、onclick 的 div)
所有标志可以自由组合。`-o` 仅在同时使用 `-a` 时适用。示例:`$B snapshot -i -a -C -o /tmp/annotated.png`
**引用编号:** @e 引用按树顺序顺序分配(@e1, @e2, ...)。来自 `-C` 的 @c 引用单独编号(@c1, @c2, ...)。
快照后,在任何命令中使用 @refs 作为选择器:
$B click @e3 $B fill @e4 "value" $B hover @e1
$B html @e2 $B css @e5 "color" $B attrs @e6
$B click @c1 # 光标可交互引用(来自 -C)
**输出格式:** 带 @ref ID 的缩进可访问性树,每行一个元素。
@e1 [heading] "Welcome" [level=1]
@e2 [textbox] "Email"
@e3 [button] "Submit"
导航后引用失效——`goto` 后再次运行 `snapshot`。
## 命令参考
### 导航
命令 | 描述
---|---
`back` | 后退历史
`forward` | 前进历史
`goto <url>` | 导航到 URL
`reload` | 重新加载页面
`url` | 打印当前 URL
### 读取
命令 | 描述
---|---
`accessibility` | 完整的 ARIA 树
`forms` | 表单字段为 JSON
`html [selector]` | 选择器的 innerHTML(如果未找到则抛出异常),如果未提供选择器则为完整页面 HTML
`links` | 所有链接为 "文本 → href"
`text` | 清理后的页面文本
### 交互
命令 | 描述
---|---
`click <sel>` | 点击元素
`cookie <name>=<value>` | 在当前页面域设置 cookie
`cookie-import <json>` | 从 JSON 文件导入 cookies
`cookie-import-browser [browser] [--domain d]` | 从 Comet、Chrome、Arc、Brave 或 Edge 导入 cookies(打开选择器,或使用 --domain 直接导入)
`dialog-accept [text]` | 自动接受下一个 alert/confirm/prompt。可选文本作为提示响应发送
`dialog-dismiss` | 自动取消下一个对话框
`fill <sel> <val>` | 填写输入框
`header <name>:<value>` | 设置自定义请求头(冒号分隔,敏感值自动脱敏)
`hover <sel>` | 悬停元素
`press <key>` | 按键——Enter、Tab、Escape、ArrowUp/Down/Left/Right、Backspace、Delete、Home、End、PageUp、PageDown,或修饰键如 Shift+Enter
`scroll [sel]` | 将元素滚动到视图中,如果无选择器则滚动到页面底部
`select <sel> <val>` | 按值、标签或可见文本选择下拉选项
`type <text>` | 输入到获得焦点的元素
`upload <sel> <file> [file2...]` | 上传文件
`useragent <string>` | 设置用户代理
`viewport <WxH>` | 设置视口大小
`wait <sel | \--networkidle
### 检查
命令 | 描述
---|---
`attrs <sel | @ref>`
`console [--clear | \--errors]`
`cookies` | 所有 cookies 为 JSON
`css <sel> <prop>` | 计算后的 CSS 值
`dialog [--clear]` | 对话框消息
`eval <file>` | 从文件运行 JavaScript 并以字符串形式返回结果(路径必须在 /tmp 或 cwd 下)
`is <prop> <sel>` | 状态检查(visible/hidden/enabled/disabled/checked/editable/focused)
`js <expr>` | 运行 JavaScript 表达式并以字符串形式返回结果
`network [--clear]` | 网络请求
`perf` | 页面加载时间
`storage [set k v]` | 读取所有 localStorage + sessionStorage 为 JSON,或设置以写入 localStorage
### 视觉
命令 | 描述
---|---
`diff <url1> <url2>` | 页面间的文本差异
`pdf [path]` | 保存为 PDF
`responsive [prefix]` | 在移动端(375x812)、平板(768x1024)、桌面端(1280x720)截图。保存为 {prefix}-mobile.png 等
`screenshot [--viewport] [--clip x,y,w,h] [selector | @ref] [path]`
### 快照
命令 | 描述
---|---
`snapshot [flags]` | 带有用于元素选择的 @e 引用的可访问性树。标志:-i 仅可交互,-c 紧凑,-d N 深度限制,-s sel 范围,-D 与先前的 diff,-a 注释截图,-o path 输出,-C 光标可交互 @c 引用
### 元命令
命令 | 描述
---|---
`chain` | 从 JSON stdin 运行命令。格式:[["cmd","arg1",...],...]
### 标签页
命令 | 描述
---|---
`closetab [id]` | 关闭标签页
`newtab [url]` | 打开新标签页
`tab <id>` | 切换到标签页
`tabs` | 列出打开的标签页
### 服务器
命令 | 描述
---|---
`handoff [message]` | 在当前页面打开可见的 Chrome 供用户接管
`restart` | 重启服务器
`resume` | 用户接管后重新快照,将控制权交还给 AI
`status` | 健康检查
`stop` | 关闭服务器
## 提示
1. **导航一次,查询多次。** `goto` 加载页面;然后 `text`、`js`、`screenshot` 都立即访问已加载的页面。
2. **首先使用 `snapshot -i`。** 查看所有可交互元素,然后通过引用点击/填写。无需猜测 CSS 选择器。
3. **使用 `snapshot -D` 进行验证。** 基线 → 操作 → diff。准确查看发生了什么变化。
4. **使用 `is` 进行断言。** `is visible .modal` 比解析页面文本更快、更可靠。
5. **使用 `snapshot -a` 作为证据。** 带注释的截图非常适合 bug 报告。
6. **使用 `snapshot -C` 处理棘手的 UI。** 查找可访问性树遗漏的可点击 div。
7. **操作后检查 `console`。** 捕获未在视觉上显示的 JS 错误。
8. **使用 `chain` 处理长流程。** 单条命令,无每步 CLI 开销。
每周安装量
1.5K
仓库
[garrytan/gstack](https://github.com/garrytan/gstack "garrytan/gstack")
GitHub 星标
40.7K
首次出现
12 天前
安全审计
[Gen Agent Trust HubPass](/garrytan/gstack/gstack/security/agent-trust-hub)[SocketWarn](/garrytan/gstack/gstack/security/socket)[SnykWarn](/garrytan/gstack/gstack/security/snyk)
安装于
codex1.4K
opencode1.4K
gemini-cli1.4K
cursor1.4K
github-copilot1.4K
kimi-cli1.4K
_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
_CONTRIB=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true)
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
mkdir -p ~/.gstack/analytics
echo '{"skill":"gstack","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done
If PROACTIVE is "false", do not proactively suggest gstack skills — only invoke them when the user explicitly asks. The user opted out of proactive suggestions.
If output shows UPGRADE_AVAILABLE <old> <new>: read ~/.claude/skills/gstack/gstack-upgrade/SKILL.md and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If JUST_UPGRADED <from> <to>: tell user "Running gstack v{to} (just updated!)" and continue.
If LAKE_INTRO is no: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the Boil the Lake principle — always do the complete thing when AI makes the marginal cost near-zero. Read more: https://garryslist.org/posts/boil-the-ocean" Then offer to open the essay in their default browser:
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
Only run open if the user says yes. Always run touch to mark as seen. This only happens once.
If TEL_PROMPTED is no AND LAKE_INTRO is yes: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion:
Help gstack get better! Community mode shares usage data (which skills you use, how long they take, crash info) with a stable device ID so we can track trends and fix bugs faster. No code, file paths, or repo names are ever sent. Change anytime with
gstack-config set telemetry off.
Options:
If A: run ~/.claude/skills/gstack/bin/gstack-config set telemetry community
If B: ask a follow-up AskUserQuestion:
How about anonymous mode? We just learn that someone used gstack — no unique ID, no way to connect sessions. Just a counter that helps us know if anyone's out there.
Options:
If B→A: run ~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous If B→B: run ~/.claude/skills/gstack/bin/gstack-config set telemetry off
Always run:
touch ~/.gstack/.telemetry-prompted
This only happens once. If TEL_PROMPTED is yes, skip this entirely.
ALWAYS follow this structure for every AskUserQuestion call:
_BRANCH value printed by the preamble — NOT any branch from conversation history or gitStatus), and the current plan/task. (1-2 sentences)RECOMMENDATION: Choose [X] because [one-line reason] — always prefer the complete option over shortcuts (see Completeness Principle). Include Completeness: X/10 for each option. Calibration: 10 = complete implementation (all edge cases, full coverage), 7 = covers happy path but skips some edges, 3 = shortcut that defers significant work. If both options are 8+, pick the higher; if one is ≤5, flag it.A) ... B) ... C) ... — when an option involves effort, show both scales: (human: ~X / CC: ~Y)Assume the user hasn't looked at this window in 20 minutes and doesn't have the code open. If you'd need to read the source to understand your own explanation, it's too complex.
Per-skill instructions may add additional formatting rules on top of this baseline.
AI-assisted coding makes the marginal cost of completeness near-zero. When you present options:
| Task type | Human team | CC+gstack | Compression |
|---|---|---|---|
| Boilerplate / scaffolding | 2 days | 15 min | ~100x |
| Test writing | 1 day | 15 min | ~50x |
| Feature implementation | 1 week | 30 min | ~30x |
| Bug fix + regression test | 4 hours | 15 min | ~20x |
| Architecture / design | 2 days | 4 hours | ~5x |
| Research / exploration | 1 day | 3 hours | ~3x |
Anti-patterns — DON'T do this:
REPO_MODE from the preamble tells you who owns issues in this repo:
solo — One person does 80%+ of the work. They own everything. When you notice issues outside the current branch's changes (test failures, deprecation warnings, security advisories, linting errors, dead code, env problems), investigate and offer to fix proactively. The solo dev is the only person who will fix it. Default to action.collaborative — Multiple active contributors. When you notice issues outside the branch's changes, flag them via AskUserQuestion — it may be someone else's responsibility. Default to asking, not fixing.unknown — Treat as collaborative (safer default — ask before fixing).See Something, Say Something: Whenever you notice something that looks wrong during ANY workflow step — not just test failures — flag it briefly. One sentence: what you noticed and its impact. In solo mode, follow up with "Want me to fix it?" In collaborative mode, just flag it and move on.
Never let a noticed issue silently pass. The whole point is proactive communication.
Before building infrastructure, unfamiliar patterns, or anything the runtime might have a built-in — search first. Read ~/.claude/skills/gstack/ETHOS.md for the full philosophy.
Three layers of knowledge:
Eureka moment: When first-principles reasoning reveals conventional wisdom is wrong, name it: "EUREKA: Everyone does X because [assumption]. But [evidence] shows this is wrong. Y is better because [reasoning]."
Log eureka moments:
jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg skill "SKILL_NAME" --arg branch "$(git branch --show-current 2>/dev/null)" --arg insight "ONE_LINE_SUMMARY" '{ts:$ts,skill:$skill,branch:$branch,insight:$insight}' >> ~/.gstack/analytics/eureka.jsonl 2>/dev/null || true
Replace SKILL_NAME and ONE_LINE_SUMMARY. Runs inline — don't stop the workflow.
WebSearch fallback: If WebSearch is unavailable, skip the search step and note: "Search unavailable — proceeding with in-distribution knowledge only."
If _CONTRIB is true: you are in contributor mode. You're a gstack user who also helps make it better.
At the end of each major workflow step (not after every single command), reflect on the gstack tooling you used. Rate your experience 0 to 10. If it wasn't a 10, think about why. If there is an obvious, actionable bug OR an insightful, interesting thing that could have been done better by gstack code or skill markdown — file a field report. Maybe our contributor will help make us better!
Calibration — this is the bar: For example, $B js "await fetch(...)" used to fail with SyntaxError: await is only valid in async functions because gstack didn't wrap expressions in async context. Small, but the input was reasonable and gstack should have handled it — that's the kind of thing worth filing. Things less consequential than this, ignore.
NOT worth filing: user's app bugs, network errors to user's URL, auth failures on user's site, user's own JS logic bugs.
To file: write ~/.gstack/contributor-logs/{slug}.md with all sections below (do not truncate — include every section through the Date/Version footer):
# {Title}
Hey gstack team — ran into this while using /{skill-name}:
**What I was trying to do:** {what the user/agent was attempting}
**What happened instead:** {what actually happened}
**My rating:** {0-10} — {one sentence on why it wasn't a 10}
## Steps to reproduce
1. {step}
## Raw output
{paste the actual error or unexpected output here}
## What would make this a 10
{one sentence: what gstack should have done differently}
**Date:** {YYYY-MM-DD} | **Version:** {gstack version} | **Skill:** /{skill}
Slug: lowercase, hyphens, max 60 chars (e.g. browse-js-no-await). Skip if file already exists. Max 3 reports per session. File inline and continue — don't stop the workflow. Tell user: "Filed gstack field report: {title}"
When completing a skill workflow, report status using one of:
It is always OK to stop and say "this is too hard for me" or "I'm not confident in this result."
Bad work is worse than no work. You will not be penalized for escalating.
Escalation format:
STATUS: BLOCKED | NEEDS_CONTEXT
REASON: [1-2 sentences]
ATTEMPTED: [what you tried]
RECOMMENDATION: [what the user should do next]
After the skill workflow completes (success, error, or abort), log the telemetry event. Determine the skill name from the name: field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted).
PLAN MODE EXCEPTION — ALWAYS RUN: This command writes telemetry to ~/.gstack/analytics/ (user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. Skipping this command loses session duration and outcome data.
Run this bash:
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
~/.claude/skills/gstack/bin/gstack-telemetry-log \
--skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \
--used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
Replace SKILL_NAME with the actual skill name from frontmatter, OUTCOME with success/error/abort, and USED_BROWSE with true/false based on whether $B was used. If you cannot determine the outcome, use "unknown". This runs in the background and never blocks the user.
When you are in plan mode and about to call ExitPlanMode:
## GSTACK REVIEW REPORT section.bash ~/.claude/skills/gstack/bin/gstack-review-read
Then write a ## GSTACK REVIEW REPORT section to the end of the plan file:
---CONFIG---): format the standard report table with runs/status/findings per skill, same format as the review skills use.NO_REVIEWS or empty: write this placeholder table:
## GSTACK REVIEW REPORT
Review | Trigger | Why | Runs | Status | Findings
---|---|---|---|---|---
CEO Review | `/plan-ceo-review` | Scope & strategy | 0 | — | —
Codex Review | `/codex review` | Independent 2nd opinion | 0 | — | —
Eng Review | `/plan-eng-review` | Architecture & tests (required) | 0 | — | —
Design Review | `/plan-design-review` | UI/UX gaps | 0 | — | —
**VERDICT:** NO REVIEWS YET — run `/autoplan` for full review pipeline, or individual reviews above. ```
**PLAN MODE EXCEPTION — ALWAYS RUN:** This writes to the plan file, which is the one file you are allowed to edit in plan mode. The plan file review report is part of the plan's living status.
If `PROACTIVE` is `false`: do NOT proactively suggest other gstack skills during this session. Only run skills the user explicitly invokes. This preference persists across sessions via `gstack-config`.
# gstack browse: QA Testing & Dogfooding
Persistent headless Chromium. First call auto-starts (~3s), then ~100-200ms per command. Auto-shuts down after 30 min idle. State persists between calls (cookies, tabs, sessions).
## SETUP (run this check BEFORE any browse command)
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
B=""
[ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && B="$_ROOT/.claude/skills/gstack/browse/dist/browse"
[ -z "$B" ] && B=~/.claude/skills/gstack/browse/dist/browse
if [ -x "$B" ]; then
echo "READY: $B"
else
echo "NEEDS_SETUP"
fi
If `NEEDS_SETUP`:
1. Tell the user: "gstack browse needs a one-time build (~10 seconds). OK to proceed?" Then STOP and wait.
2. Run: `cd <SKILL_DIR> && ./setup`
3. If `bun` is not installed: `curl -fsSL https://bun.sh/install | bash`
## IMPORTANT
* Use the compiled binary via Bash: `$B <command>`
* NEVER use `mcp__claude-in-chrome__*` tools. They are slow and unreliable.
* Browser persists between calls — cookies, login sessions, and tabs carry over.
* Dialogs (alert/confirm/prompt) are auto-accepted by default — no browser lockup.
* **Show screenshots:** After `$B screenshot`, `$B snapshot -a -o`, or `$B responsive`, always use the Read tool on the output PNG(s) so the user can see them. Without this, screenshots are invisible.
## QA Workflows
### Test a user flow (login, signup, checkout, etc.)
# 1. Go to the page
$B goto https://app.example.com/login
# 2. See what's interactive
$B snapshot -i
# 3. Fill the form using refs
$B fill @e3 "test@example.com"
$B fill @e4 "password123"
$B click @e5
# 4. Verify it worked
$B snapshot -D # diff shows what changed after clicking
$B is visible ".dashboard" # assert the dashboard appeared
$B screenshot /tmp/after-login.png
### Verify a deployment / check prod
$B goto https://yourapp.com
$B text # read the page — does it load?
$B console # any JS errors?
$B network # any failed requests?
$B js "document.title" # correct title?
$B is visible ".hero-section" # key elements present?
$B screenshot /tmp/prod-check.png
### Dogfood a feature end-to-end
# Navigate to the feature
$B goto https://app.example.com/new-feature
# Take annotated screenshot — shows every interactive element with labels
$B snapshot -i -a -o /tmp/feature-annotated.png
# Find ALL clickable things (including divs with cursor:pointer)
$B snapshot -C
# Walk through the flow
$B snapshot -i # baseline
$B click @e3 # interact
$B snapshot -D # what changed? (unified diff)
# Check element states
$B is visible ".success-toast"
$B is enabled "#next-step-btn"
$B is checked "#agree-checkbox"
# Check console for errors after interactions
$B console
### Test responsive layouts
# Quick: 3 screenshots at mobile/tablet/desktop
$B goto https://yourapp.com
$B responsive /tmp/layout
# Manual: specific viewport
$B viewport 375x812 # iPhone
$B screenshot /tmp/mobile.png
$B viewport 1440x900 # Desktop
$B screenshot /tmp/desktop.png
# Element screenshot (crop to specific element)
$B screenshot "#hero-banner" /tmp/hero.png
$B snapshot -i
$B screenshot @e3 /tmp/button.png
# Region crop
$B screenshot --clip 0,0,800,600 /tmp/above-fold.png
# Viewport only (no scroll)
$B screenshot --viewport /tmp/viewport.png
### Test file upload
$B goto https://app.example.com/upload
$B snapshot -i
$B upload @e3 /path/to/test-file.pdf
$B is visible ".upload-success"
$B screenshot /tmp/upload-result.png
### Test forms with validation
$B goto https://app.example.com/form
$B snapshot -i
# Submit empty — check validation errors appear
$B click @e10 # submit button
$B snapshot -D # diff shows error messages appeared
$B is visible ".error-message"
# Fill and resubmit
$B fill @e3 "valid input"
$B click @e10
$B snapshot -D # diff shows errors gone, success state
### Test dialogs (delete confirmations, prompts)
# Set up dialog handling BEFORE triggering
$B dialog-accept # will auto-accept next alert/confirm
$B click "#delete-button" # triggers confirmation dialog
$B dialog # see what dialog appeared
$B snapshot -D # verify the item was deleted
# For prompts that need input
$B dialog-accept "my answer" # accept with text
$B click "#rename-button" # triggers prompt
### Test authenticated pages (import real browser cookies)
# Import cookies from your real browser (opens interactive picker)
$B cookie-import-browser
# Or import a specific domain directly
$B cookie-import-browser comet --domain .github.com
# Now test authenticated pages
$B goto https://github.com/settings/profile
$B snapshot -i
$B screenshot /tmp/github-profile.png
### Compare two pages / environments
$B diff https://staging.app.com https://prod.app.com
### Multi-step chain (efficient for long flows)
echo '[
["goto","https://app.example.com"],
["snapshot","-i"],
["fill","@e3","test@test.com"],
["fill","@e4","password"],
["click","@e5"],
["snapshot","-D"],
["screenshot","/tmp/result.png"]
]' | $B chain
## Quick Assertion Patterns
# Element exists and is visible
$B is visible ".modal"
# Button is enabled/disabled
$B is enabled "#submit-btn"
$B is disabled "#submit-btn"
# Checkbox state
$B is checked "#agree"
# Input is editable
$B is editable "#name-field"
# Element has focus
$B is focused "#search-input"
# Page contains text
$B js "document.body.textContent.includes('Success')"
# Element count
$B js "document.querySelectorAll('.list-item').length"
# Specific attribute value
$B attrs "#logo" # returns all attributes as JSON
# CSS property
$B css ".button" "background-color"
## Snapshot System
The snapshot is your primary tool for understanding and interacting with pages.
-i --interactive Interactive elements only (buttons, links, inputs) with @e refs
-c --compact Compact (no empty structural nodes)
-d <N> --depth Limit tree depth (0 = root only, default: unlimited)
-s <sel> --selector Scope to CSS selector
-D --diff Unified diff against previous snapshot (first call stores baseline)
-a --annotate Annotated screenshot with red overlay boxes and ref labels
-o <path> --output Output path for annotated screenshot (default: <temp>/browse-annotated.png)
-C --cursor-interactive Cursor-interactive elements (@c refs — divs with pointer, onclick)
All flags can be combined freely. `-o` only applies when `-a` is also used. Example: `$B snapshot -i -a -C -o /tmp/annotated.png`
**Ref numbering:** @e refs are assigned sequentially (@e1, @e2, ...) in tree order. @c refs from `-C` are numbered separately (@c1, @c2, ...).
After snapshot, use @refs as selectors in any command:
$B click @e3 $B fill @e4 "value" $B hover @e1
$B html @e2 $B css @e5 "color" $B attrs @e6
$B click @c1 # cursor-interactive ref (from -C)
**Output format:** indented accessibility tree with @ref IDs, one element per line.
@e1 [heading] "Welcome" [level=1]
@e2 [textbox] "Email"
@e3 [button] "Submit"
Refs are invalidated on navigation — run `snapshot` again after `goto`.
## Command Reference
### Navigation
Command | Description
---|---
`back` | History back
`forward` | History forward
`goto <url>` | Navigate to URL
`reload` | Reload page
`url` | Print current URL
### Reading
Command | Description
---|---
`accessibility` | Full ARIA tree
`forms` | Form fields as JSON
`html [selector]` | innerHTML of selector (throws if not found), or full page HTML if no selector given
`links` | All links as "text → href"
`text` | Cleaned page text
### Interaction
Command | Description
---|---
`click <sel>` | Click element
`cookie <name>=<value>` | Set cookie on current page domain
`cookie-import <json>` | Import cookies from JSON file
`cookie-import-browser [browser] [--domain d]` | Import cookies from Comet, Chrome, Arc, Brave, or Edge (opens picker, or use --domain for direct import)
`dialog-accept [text]` | Auto-accept next alert/confirm/prompt. Optional text is sent as the prompt response
`dialog-dismiss` | Auto-dismiss next dialog
`fill <sel> <val>` | Fill input
`header <name>:<value>` | Set custom request header (colon-separated, sensitive values auto-redacted)
`hover <sel>` | Hover element
`press <key>` | Press key — Enter, Tab, Escape, ArrowUp/Down/Left/Right, Backspace, Delete, Home, End, PageUp, PageDown, or modifiers like Shift+Enter
`scroll [sel]` | Scroll element into view, or scroll to page bottom if no selector
`select <sel> <val>` | Select dropdown option by value, label, or visible text
`type <text>` | Type into focused element
`upload <sel> <file> [file2...]` | Upload file(s)
`useragent <string>` | Set user agent
`viewport <WxH>` | Set viewport size
`wait <sel | \--networkidle
### Inspection
Command | Description
---|---
`attrs <sel | @ref>`
`console [--clear | \--errors]`
`cookies` | All cookies as JSON
`css <sel> <prop>` | Computed CSS value
`dialog [--clear]` | Dialog messages
`eval <file>` | Run JavaScript from file and return result as string (path must be under /tmp or cwd)
`is <prop> <sel>` | State check (visible/hidden/enabled/disabled/checked/editable/focused)
`js <expr>` | Run JavaScript expression and return result as string
`network [--clear]` | Network requests
`perf` | Page load timings
`storage [set k v]` | Read all localStorage + sessionStorage as JSON, or set to write localStorage
### Visual
Command | Description
---|---
`diff <url1> <url2>` | Text diff between pages
`pdf [path]` | Save as PDF
`responsive [prefix]` | Screenshots at mobile (375x812), tablet (768x1024), desktop (1280x720). Saves as {prefix}-mobile.png etc.
`screenshot [--viewport] [--clip x,y,w,h] [selector | @ref] [path]`
### Snapshot
Command | Description
---|---
`snapshot [flags]` | Accessibility tree with @e refs for element selection. Flags: -i interactive only, -c compact, -d N depth limit, -s sel scope, -D diff vs previous, -a annotated screenshot, -o path output, -C cursor-interactive @c refs
### Meta
Command | Description
---|---
`chain` | Run commands from JSON stdin. Format: [["cmd","arg1",...],...]
### Tabs
Command | Description
---|---
`closetab [id]` | Close tab
`newtab [url]` | Open new tab
`tab <id>` | Switch to tab
`tabs` | List open tabs
### Server
Command | Description
---|---
`handoff [message]` | Open visible Chrome at current page for user takeover
`restart` | Restart server
`resume` | Re-snapshot after user takeover, return control to AI
`status` | Health check
`stop` | Shutdown server
## Tips
1. **Navigate once, query many times.** `goto` loads the page; then `text`, `js`, `screenshot` all hit the loaded page instantly.
2. **Use`snapshot -i` first.** See all interactive elements, then click/fill by ref. No CSS selector guessing.
3. **Use`snapshot -D` to verify.** Baseline → action → diff. See exactly what changed.
4. **Use`is` for assertions.** `is visible .modal` is faster and more reliable than parsing page text.
5. **Use`snapshot -a` for evidence.** Annotated screenshots are great for bug reports.
6. **Use`snapshot -C` for tricky UIs.** Finds clickable divs that the accessibility tree misses.
7. **Check`console` after actions.** Catch JS errors that don't surface visually.
8. **Use`chain` for long flows.** Single command, no per-step CLI overhead.
Weekly Installs
1.5K
Repository
[garrytan/gstack](https://github.com/garrytan/gstack "garrytan/gstack")
GitHub Stars
40.7K
First Seen
12 days ago
Security Audits
[Gen Agent Trust HubPass](/garrytan/gstack/gstack/security/agent-trust-hub)[SocketWarn](/garrytan/gstack/gstack/security/socket)[SnykWarn](/garrytan/gstack/gstack/security/snyk)
Installed on
codex1.4K
opencode1.4K
gemini-cli1.4K
cursor1.4K
github-copilot1.4K
kimi-cli1.4K
97,600 周安装