ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

wigolo watch 实战:用 `watch` 工具监听 changelog 变更并通过 Webhook 自动推送

2026/9/18 14:27:58 拓冰建站 浏览量
wigolo watch 实战:用 `watch` 工具监听 changelog 变更并通过 Webhook 自动推送 wigolo watch 实战用watch工具监听 changelog 变更并通过 Webhook 自动推送【免费下载链接】wigoloThe go-to web for your AI coding agent — local-first search, fetch, crawl research over MCP. No API keys, no cloud, $0/query. Public beta.项目地址: https://gitcode.com/GitHub_Trending/wi/wigolowatch是 wigolo 提供的变更监听工具对一个 URL 注册监听任务后wigolo 会抓取页面、对提取出的正文内容计算哈希下次检查时只要哈希发生变化就会产出changed: true的变更报告——既可以在下一次检查中内联返回也可以通过 Webhook 以 POST JSON 形式推送到你自己的端点。本文以仓库自带的 examples/watch-changelog-webhook/README.md 为骨架结合 watch.sh 一键脚本与src/watch/、src/tools/下的源码实现完整演示注册任务 → 查看任务 → 按需检查 → 解读 diff → 清理的端到端流程并深入讲解调度模型、Webhook 投递与 SSRF 防护的底层原理帮助你把它接入自己的自动化流水线如 CI、消息通知、数据同步。一、watch的核心机制快照、内容哈希与变更报告watch工具做的事情可以概括为三步抓取快照 → 哈希正文 → 对比哈希。一次检查check的完整调用链位于 src/watch/scheduler.ts 的runCheck重新执行 SSRF 校验检查时刻会再次对 job 的 URL 与 webhook 地址调用guardUrl注册时已校验过一次这里再校验是为了让策略收紧后旧任务不过期豁免抓取页面复用fetch工具链路传入include_full_markdown: true与force_refresh: true走 src/tools/fetch.ts 的智能路由普通 http 直接抓取需要 JS 的页面可升级到 Playwright 渲染计算内容指纹优先采用fetch返回的content_hash——它是完整提取正文fresh 或来自缓存的整页内容的 sha256与展示用的 markdown 是否被截断无关只有该字段缺失时才回退到对 markdown 本地做 sha256源码注释明确指出这是对旧缓存行/测试替身的防御对比基线首次成功检查时记录基线报告为changed: false 当前哈希哈希一致则照常记录检查时间报告changed: false哈希不一致则报告changed: true并携带previous_hash/current_hash同时写入diff_summary标记变更规模最后更新last_check_at与last_content_hashWebhook 投递若任务注册时指定了notification且非inline则在检测到变更时把报告 POST 到目标端点见第五节。每次检查结束都会通过recordChecksrc/watch/store.ts更新last_check_at即使抓取失败也会更新——这是为了避免任务反复锤打一个永久损坏的 URL。单次检查的返回结构为ChangeReport{ url, changed, current_hash, previous_hash?, diff_summary?, error? }。二、一键体验运行仓库自带的watch.sh仓库在 examples/watch-changelog-webhook/ 下提供了一个可直接运行的 Bash 脚本 watch.sh默认监听 Node.js 官方博客https://nodejs.org/en/blog。要求本机具备node 20与jq./watch.sh # 默认监听 https://nodejs.org/en/blog URLhttps://your-site/changelog ./watch.sh # 换成任何你关心的 changelog 页面 WIGOLOwigolo ./watch.sh # 或用已安装的二进制替代 npx wigolo脚本内部默认通过npx wigolo调用 CLI并以--json输出 jq解析来组织输出。它依次演示了五个步骤你会在终端看到类似下面的真实输出 1. register a watch on https://nodejs.org/en/blog job id: 74bec5cfdc2cb8bc36a728e46ede89a1b7e7b2a731158771e47674ee6358edfd 2. list registered jobs 74bec5cfdc2c… active every 3600s https://nodejs.org/en/blog 3. on-demand check (first check records the baseline) { url: https://nodejs.org/en/blog, changed: false, current_hash: 3e600c4fc579 } 4. what a change looks like: the diff engines report --- old new -1,3 1,4 -## v2.4.0 ## v2.5.0 - Added container queries guide - Added subgrid examples - Fixed typo in grid docs 5. clean up {removed_jobs:1}对输出做逐段解读第 1 步watch add url --interval 3600 --json注册任务返回的job id是一个 sha256 指纹字符串详见第四节幂等创建后续run/rm都靠它定位第 2 步watch list列出已注册任务展示状态active、间隔every 3600s与目标 URL第 3 步watch run id触发一次按需检查。第一次检查只会记录基线返回changed: false和current_hash并不会误报变更第 4 步脚本用wigolo diff --old … --new … --output unified --json把两段内联文本交给 diff 引擎演示当哈希发生变化时 diff 报告长什么样——统一格式unified下每一行都以-/前缀标明删除/新增第 5 步watch rm id删除任务返回{removed_jobs:1}完成清理。真实场景中第 4 步的上一次正文由任务持久化wigolo diff url会拿页面与缓存副本做对比从而还原出previous_hash→current_hash之间到底改了什么。三、CLI 命令速查watch 功能在 CLI 下的命令形态如下docs/cli.mdwigolo watch add url --intervalSECONDS # 注册监听任务 wigolo watch list # 列出所有任务 wigolo watch run id # 按需执行一次检查 wigolo watch rm id # 删除任务配套的 diff 命令wigolo diff url # 对比页面与缓存副本 wigolo diff --oldtext --newtext [--output...] [--granularity...]diff 工具支持三种输出形态unified统一 diff/hunks分块/summary摘要与三种粒度line/word/section由 src/tools/diff.ts 校验后交给 src/cache/diff-engine.ts 计算内部基于 LCS最长公共子序列DP 表回溯出有序编辑脚本buildEditScript并统计added/removed/modified计数。两个硬性上限值得注意行数超过DIFF_LINE_CAP 5000时跳过 LCS 退化为仅摘要单侧 token 超过DIFF_TOKEN_CAP 50_000时回退到行粒度并携带truncated: true这是为了避免 LCS 的 O(m×n) DP 表把内存打爆。四、任务注册参数与持久化watch 的完整参数面在 docs/tools.md 的watch一节有表格说明在 src/tools/watch.ts 中对应WatchJobInput参数类型说明actionenumcreate/list/check/pause/resume/delete必填url/urlsstring / string[]单个或批量创建二者互斥不能同时传interval_secondsnumber创建时必填最小 60 秒低于此值直接拒绝以尊重目标站点限流selectorstring可选用于把 diff 限定到 CSS 选择器命中的子树notificationstringinline默认变更在下一次检查中返回或一个 webhook URLwebhook 目标同样受 SSRF 防护job_idstringcheck/pause/resume/delete必填几个由源码确认的行为细节批量上限urls批量创建上限为MAX_WATCH_BATCH_SIZE 1000且批量创建会先全部通过guardUrl校验再落库——任何一个 URL 非法就整体失败fail-closed避免半批任务残留见 src/tools/watch.ts 中 create 分支。幂等创建任务 id 不是随机 UUID而是对url interval_seconds selector三元组做的 sha256 指纹src/watch/store.ts 的fingerprint。重复注册相同三元组会直接返回已存在的 job不会插入重复行。持久化任务存储在 SQLitewatch_jobs表字段含url、interval_seconds、selector、last_check_at、last_content_hash、status、notification、created_atstatus支持active/paused对应pause/resume动作。每个 job 还会在读取时计算出staleness_seconds正值表示已逾期秒数负值表示距下次检查还有多少秒。关于 selector 的现状目前 fetch 路径返回整页 markdownselector列虽已持久化保证接口前向兼容但 diff 仍是整页对比——源码注释明确说明selector-scoped extraction是后续功能现在仅记录在日志中。使用该参数时请知晓此限制。一个典型的注册请求REST / MCP 工具形态如{ action: create, url: https://go.dev/doc/devel/release, interval_seconds: 3600, notification: inline }五、Webhook 投递--notify与接收端注册任务时传入--notify之后每次检测到变更wigolo 都会把变更报告以 JSON 形式 POST 到你的端点npx wigolo watch add https://nodejs.org/en/blog --interval 3600 \ --notify https://hooks.example.com/wigolo投递的 payload 与检测到变更时的ChangeReport结构一致并补充job_id{ job_id: 74bec5cf…, url: https://nodejs.org/en/blog, changed: true, previous_hash: 3e600c…, current_hash: 9f41aa…, diff_summary: … }接收端只需几行 Node放到任何你已有的自动化设施里运行即可// receiver.mjs — node receiver.mjs import http from node:http; http.createServer((req, res) { let body ; req.on(data, (c) (body c)); req.on(end, () { console.log(change:, body); res.end(ok); }); }).listen(8787);从源码看投递是极简实现src/watch/scheduler.ts 的deliverWebhook直接使用 Node 20 内置fetchPOSTcontent-type: application/jsonfire-and-forget——失败仅记录watch webhook delivery failed日志不重试、不排队、不背压。这意味着 webhook 投递按设计是 best-effort而不是可靠投递保证对变更通知类场景足够若要必须送达请自行叠加重试队列。六、调度模型懒执行没有常驻后台watch 没有独立的守护线程采用**懒执行lazy execution**模型这是理解整个功能的关键按需检查watch run id是单次、立即的检查定时检查只有当长驻进程存在时才会触发——wigolo serve守护进程或一个存活的 MCP 会话期间每次任何其他工具被调用后dispatch 链都会调用scheduleOverdueCheck(router)src/watch/scheduler.ts它用setImmediate把triggerOverdueJobs挂到后台查询所有status active且last_check_at interval已到期的任务并逐个runCheck。配套的两个工程细节不阻塞调用方scheduleOverdueCheck故意吞掉返回的 Promise绝不让逾期任务拖慢当前工具的延迟重入保护triggerOverdueJobs内部有进程内firing标志防止某次检查触发的 fetch 又回到调度器形成递归。因此 docs/tools.md 中的那句结论非常准确一次性 CLI 调用只能注册和查看任务不能调度要真正跑定时检查需要一个存活的wigolo serve或 MCP 会话。任务只需注册一次同一台机器上任何一个存活的长驻 wigolo 都会接管它们。七、安全设计SSRF 防护与重定向拒绝webhook 目标以及被监听的 URL必须是公网 http(s) 端点。wigolo 的 SSRF 守卫src/watch/ssrf.ts 的guardUrl在注册时就对两类地址强制校验并拒绝非http:/https:协议file://、ftp://、data:、javascript:等环回地址localhost、127.0.0.0/8、::1保留地址0.0.0.0RFC 1918 私网段10/8、172.16/12、192.168/16链路本地169.254/16、fe80::/10——含各大云厂商的 metadata 端点IPv6 唯一本地地址fc00::/7及 IPv6 环回还包括::ffff:127.0.0.1这类 IPv4 映射形式和::127.0.0.1兼容形式源码用正则把十六进制尾段还原成点分十进制再判定堵住了这些经典绕过手法。同时runCheck在检查时刻会再次执行guardUrl注册时校验 运行时复检保证策略收紧后旧任务不会被豁免进被禁地址空间。此外投递端deliverWebhook特意使用redirect: manual并拒绝所有 3xx——因为一个公网 webhook 地址可能被目标服务器 307/308 重定向到http://127.0.0.1/admin若跟随默认重定向就会在投递时刻绕过 SSRF 守卫。因此重定向的 webhook 目标会被当作一次投递失败绝不会被盲从。给接收端一个公网 HTTPS 入口或你现有栈已信任的隧道并在目标站点层面留意重定向行为。八、将 watch 接入你的自动化平台把 watch 移植到自动化平台有两条现成路径REST / MCPwatch 是 wigolo 的工具之一同样的功能可通过 REST API 或 MCP 协议暴露供 n8n 等平台远程调用仓库提供了完整的 n8n-remote-mcp 示例含可直接导入的 workflow.json纯脚本把 watch.sh 的模式--json输出 jq解析 本地receiver.mjs搬进你自己的 cron 或 CI 步骤即可无需任何云服务。一个典型的落地组合是watch add changelog --interval 3600 --notify https://你的端点 一个公开接收端如 watch.sh 第 1821 行注释展示的 webhook 变体由长驻的wigolo serve兜底调度变更一到便触发你的下游逻辑发消息、触发构建、更新索引等。这套链路完整示例都在 examples/watch-changelog-webhook/配合 docs/tools.md 的 watch 参数表与 docs/cli.md 的 CLI 形态即可直接复制到自己的项目中使用。【免费下载链接】wigoloThe go-to web for your AI coding agent — local-first search, fetch, crawl research over MCP. No API keys, no cloud, $0/query. Public beta.项目地址: https://gitcode.com/GitHub_Trending/wi/wigolo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考