# linkpulse **Repository Path**: tomlen/linkpulse ## Basic Information - **Project Name**: linkpulse - **Description**: Post-publication link patrol: fake-alive exposure (200 + 404 body != alive), full redirect-chain transparency, baseline diff for cron. Zero-dep single file. - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-25 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # linkpulse [English](#english) | 简体中文 # 中文 **发布物死活巡检官** —— 发出去的每一个链接(阅读原文 / CDN 图床 / 安装 curl 命令)都是你对读者的承诺。 仓库改名、分支变动、CDN 404、redirect 悄悄换了目标——读者永远先于你知道。linkpulse 把这些承诺盯起来。 零依赖单文件 CLI,Python 3.8+ 标准库,拷走就能跑。macOS / Linux / Windows 通吃。 ## 真实战绩(开发首日实战逮住的 4 个真相) | # | 实测发现 | linkpulse 判定 | |---|---|---| | 1 | `cdn.jsdelivr.net/gh/` 对 GitHub 仓库文件 301 跳到 `raw.githubusercontent.com`(国内不可达域名),且 5 连发 4 次超时 1 次成功——**闪断实锤** | REDIRECTED / DEAD(timeout) | | 2 | jsDelivr `npm` 面直连正常(`/npm/vue@3` 200,不跳) | ALIVE | | 3 | Gitee raw 301 跳 `raw.giteeusercontent.com`(国内可达),内容完整 | REDIRECTED + 内容校验 | | 4 | GitHub API 对不存在仓库 404(`HTTP 404`) | DEAD http_404 | 结论:**国内图床选 jsDelivr 的 `npm` 面或 Gitee raw,`gh` 面已在闪断,别再裸奔。** 这是 linkpulse 上线第一天自己量出来的。 ## 解决什么问题 * 文章里的「阅读原文」链到仓库 → **仓库哪天改名/转私,你最后一个知道** * 图床 URL 嵌进排版 HTML → **CDN 换规则/闪断,读者看到裂图** * README 里的安装 curl 命令 → **install.sh 被 404 页顶替,读者照抄翻车** * HTTP 200 ≠ 活着 → **404 落地页也是 200**,linkpulse 用死亡签名库识破假活(INV1) ## 快速开始 ```bash # 一次体检:命令行直接给 URL python3 linkpulse.py check https://gitee.com/tomlen/linkpulse https://cdn.jsdelivr.net/npm/vue@3 # 清单模式(推荐):manifest.json 管理 URL + 预期内容 + 最小字节数 python3 linkpulse.py check -f manifest.json -v # 基线巡检:与上轮 diff(新死/复活/内容变更),退出码 0/1/2 直接接 cron python3 linkpulse.py guard -f manifest.json # 自测:本地起真实 HTTP 端点,全链路 8 案 python3 linkpulse.py selftest ``` manifest.json 示例: ```json { "targets": [ {"url": "https://gitee.com/tomlen/linkpulse", "tag": "仓库页", "expect": "linkpulse"}, {"url": "https://gitee.com/tomlen/linkpulse/raw/main/linkpulse.py", "tag": "安装源", "min_bytes": 20000}, {"url": "https://cdn.jsdelivr.net/npm/linkpulse@1/", "tag": "CDN", "min_bytes": 500} ] } ``` ## 判定四级 | 判定 | 含义 | 退出码贡献 | |---|---|---| | ALIVE | 直连 200,内容过关 | 0 | | REDIRECTED | 活着但换了地址(每一跳都写进报告) | 0 | | SUSPECT | HTTP 200 但像死页:死亡签名命中 / expect 落空 / body 过小 | 1(--strict 升 2) | | DEAD | 404/5xx/超时/拒绝/TLS/重定向超限 | 2 | ## 四条不变量 | 不变量 | 内容 | 自测 | |---|---|---| | INV1 | 假活现形:200 + 死亡签名 body ≠ 活着 → SUSPECT,绝不报 ALIVE | ✅ | | INV2 | 重定向全透明:每一跳进报告;换目标 = REDIRECTED;成环/超跳 = DEAD,绝不静默吞 | ✅ | | INV3 | 单链不炸全局:DNS/超时/拒绝/TLS/HTTP 错全部分类 DEAD+原因,绝不中断整轮 | ✅ | | INV4 | 退出码确定:0/1/2,--strict 升格,脚本可放心接 cron | ✅ | 死亡签名库(内置,按域名分组 + 通配兜底):jsDelivr `Couldn't find the requested file`、GitHub raw `404: Not Found`、Gitee `页面不存在`、通用 `page not found` 等十余条。 签名只对 <2048B 的小 body 比对(真文章不会这么短);`expect` 显式命中时跳过签名启发(你声明了预期内容且命中 = 内容正确)。 ## guard 基线模式(接 cron 的正确姿势) ```bash # crontab:每天早 9 点巡检,有事件退出码非 0,配合你现有的告警通道 0 9 * * * /usr/bin/python3 /path/to/linkpulse.py guard -f /path/to/manifest.json ``` 事件类型:`NEWLY_DEAD`(上轮活这轮死)/ `REVIVED`(复活)/ `CONTENT_CHANGED`(sha256 前 16 位变化)/ `NEW_SUSPECT`。 状态存 `~/.linkpulse/state.json`(`--state` 可改)。 ## 实测免责声明 网络探测有天然波动,单次 DEAD 建议复测 2-3 次再定性;`--honor-proxy` 遵循环境代理(默认绕过,防止环境代理把探测带偏)。 ## English **linkpulse** — post-publication link patrol. Every link you publish (README install commands, CDN image URLs, "read more" targets) is a promise. Repos get renamed, CDNs 404, redirects silently change targets — readers always find out before you do. Zero-dependency single-file CLI (Python 3.8+). ```bash python3 linkpulse.py check # one-shot health check python3 linkpulse.py guard -f manifest.json # baseline mode: NEWLY_DEAD / REVIVED / CONTENT_CHANGED python3 linkpulse.py selftest # 8 real-HTTP end-to-end cases ``` Verdicts: ALIVE / REDIRECTED / SUSPECT (HTTP 200 but death-signature body, missed expect regex, or too-small body) / DEAD. Exit codes 0/1/2 (`--strict` promotes SUSPECT). Four invariants: fake-alive exposure, full redirect-chain transparency, per-URL fault isolation, deterministic exit codes. First-day real-world finding: `cdn.jsdelivr.net/gh/` now 301s to the GFW-blocked `raw.githubusercontent.com` and flaps (4/5 timeouts) — use the jsDelivr `npm` face or Gitee raw instead. ## License MIT