Hermes-agent

This commit is contained in:
Zakaria
2026-06-14 14:30:48 -04:00
commit dac4b88b94
5058 changed files with 1884848 additions and 0 deletions
@@ -0,0 +1,173 @@
---
title: "Inference Sh Cli — 通过 inference 运行 150+ AI 应用"
sidebar_label: "Inference Sh Cli"
description: "通过 inference 运行 150+ AI 应用"
---
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
# Inference Sh Cli
通过 inference.sh CLIinfsh)运行 150+ AI 应用——图像生成、视频创作、LLM、搜索、3D、社交自动化。使用终端工具。触发词:inference.sh、infsh、ai apps、flux、veo、image generation、video generation、seedream、seedance、tavily
## Skill 元数据
| | |
|---|---|
| 来源 | 可选——使用 `hermes skills install official/devops/cli` 安装 |
| 路径 | `optional-skills/devops/cli` |
| 版本 | `1.0.0` |
| 作者 | okaris |
| 许可证 | MIT |
| 平台 | linux, macos, windows |
| 标签 | `AI`, `image-generation`, `video`, `LLM`, `search`, `inference`, `FLUX`, `Veo`, `Claude` |
## 参考:完整 SKILL.md
:::info
以下是 Hermes 在该 skill 被触发时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
:::
# inference.sh CLI
通过简单的 CLI 在云端运行 150+ AI 应用。无需 GPU。
所有命令均使用**终端工具**来运行 `infsh` 命令。
## 使用场景
- 用户要求生成图像(FLUX、Reve、Seedream、Grok、Gemini image
- 用户要求生成视频(Veo、Wan、Seedance、OmniHuman
- 用户询问 inference.sh 或 infsh
- 用户希望运行 AI 应用而无需管理各个提供商的 API
- 用户要求 AI 驱动的搜索(Tavily、Exa
- 用户需要生成头像/口型同步
## 前置条件
`infsh` CLI 必须已安装并完成认证。使用以下命令检查:
```bash
infsh me
```
如未安装:
```bash
curl -fsSL https://cli.inference.sh | sh
infsh login
```
完整安装详情请参阅 `references/authentication.md`
## 工作流程
### 1. 始终先搜索
不要猜测应用名称——始终通过搜索找到正确的应用 ID:
```bash
infsh app list --search flux
infsh app list --search video
infsh app list --search image
```
### 2. 运行应用
使用搜索结果中的精确应用 ID。始终使用 `--json` 获取机器可读的输出:
```bash
infsh app run <app-id> --input '{"prompt": "your prompt here"}' --json
```
### 3. 解析输出
JSON 输出包含指向生成媒体的 URL。使用 `MEDIA:<url>` 格式将其呈现给用户以内联显示。
## 常用命令
### 图像生成
```bash
# 搜索图像应用
infsh app list --search image
# FLUX Dev with LoRA
infsh app run falai/flux-dev-lora --input '{"prompt": "sunset over mountains", "num_images": 1}' --json
# Gemini 图像生成
infsh app run google/gemini-2-5-flash-image --input '{"prompt": "futuristic city", "num_images": 1}' --json
# Seedream (ByteDance)
infsh app run bytedance/seedream-5-lite --input '{"prompt": "nature scene"}' --json
# Grok Imagine (xAI)
infsh app run xai/grok-imagine-image --input '{"prompt": "abstract art"}' --json
```
### 视频生成
```bash
# 搜索视频应用
infsh app list --search video
# Veo 3.1 (Google)
infsh app run google/veo-3-1-fast --input '{"prompt": "drone shot of coastline"}' --json
# Seedance (ByteDance)
infsh app run bytedance/seedance-1-5-pro --input '{"prompt": "dancing figure", "resolution": "1080p"}' --json
# Wan 2.5
infsh app run falai/wan-2-5 --input '{"prompt": "person walking through city"}' --json
```
### 本地文件上传
CLI 会在提供路径时自动上传本地文件:
```bash
# 放大本地图像
infsh app run falai/topaz-image-upscaler --input '{"image": "/path/to/photo.jpg", "upscale_factor": 2}' --json
# 从本地文件生成图生视频
infsh app run falai/wan-2-5-i2v --input '{"image": "/path/to/image.png", "prompt": "make it move"}' --json
# 带音频的头像
infsh app run bytedance/omnihuman-1-5 --input '{"audio": "/path/to/audio.mp3", "image": "/path/to/face.jpg"}' --json
```
### 搜索与研究
```bash
infsh app list --search search
infsh app run tavily/tavily-search --input '{"query": "latest AI news"}' --json
infsh app run exa/exa-search --input '{"query": "machine learning papers"}' --json
```
### 其他类别
```bash
# 3D 生成
infsh app list --search 3d
# 音频 / TTS
infsh app list --search tts
# Twitter/X 自动化
infsh app list --search twitter
```
## 注意事项
1. **不要猜测应用 ID**——始终先运行 `infsh app list --search <term>`。应用 ID 会变更,新应用也会频繁添加。
2. **始终使用 `--json`**——原始输出难以解析。`--json` 标志提供包含 URL 的结构化输出。
3. **检查认证状态**——如果命令因认证错误失败,请运行 `infsh login` 或确认 `INFSH_API_KEY` 已设置。
4. **长时间运行的应用**——视频生成可能需要 30-120 秒。终端工具的超时时间应该足够,但请提前告知用户可能需要等待片刻。
5. **输入格式**——`--input` 标志接受 JSON 字符串。请确保正确转义引号。
## 参考文档
- `references/authentication.md` — 安装、登录、API 密钥
- `references/app-discovery.md` — 搜索和浏览应用目录
- `references/running-apps.md` — 运行应用、输入格式、输出处理
- `references/cli-reference.md` — 完整 CLI 命令参考
@@ -0,0 +1,297 @@
---
title: "Docker 管理"
sidebar_label: "Docker 管理"
description: "管理 Docker 容器、镜像、卷、网络和 Compose 栈——生命周期操作、调试、清理及 Dockerfile 优化"
---
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
# Docker 管理
管理 Docker 容器、镜像、卷、网络和 Compose 栈——生命周期操作、调试、清理及 Dockerfile 优化。
## Skill 元数据
| | |
|---|---|
| 来源 | 可选——使用 `hermes skills install official/devops/docker-management` 安装 |
| 路径 | `optional-skills/devops/docker-management` |
| 版本 | `1.0.0` |
| 作者 | sprmn24 |
| 许可证 | MIT |
| 平台 | linux, macos, windows |
| 标签 | `docker`, `containers`, `devops`, `infrastructure`, `compose`, `images`, `volumes`, `networks`, `debugging` |
## 参考:完整 SKILL.md
:::info
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
:::
# Docker 管理
使用标准 Docker CLI 命令管理 Docker 容器、镜像、卷、网络和 Compose 栈。除 Docker 本身外无需额外依赖。
## 适用场景
- 运行、停止、重启、删除或检查容器
- 构建、拉取、推送、标记或清理 Docker 镜像
- 使用 Docker Compose(多服务栈)
- 管理卷或网络
- 调试崩溃的容器或分析日志
- 检查 Docker 磁盘使用情况或释放空间
- 审查或优化 Dockerfile
## 前提条件
- Docker Engine 已安装并运行
- 用户已加入 `docker` 组(或使用 `sudo`
- Docker Compose v2(现代 Docker 安装已包含)
快速检查:
```bash
docker --version && docker compose version
```
## 快速参考
| 任务 | 命令 |
|------|---------|
| 运行容器(后台) | `docker run -d --name NAME IMAGE` |
| 停止并删除 | `docker stop NAME && docker rm NAME` |
| 查看日志(跟踪) | `docker logs --tail 50 -f NAME` |
| 进入容器 Shell | `docker exec -it NAME /bin/sh` |
| 列出所有容器 | `docker ps -a` |
| 构建镜像 | `docker build -t TAG .` |
| Compose 启动 | `docker compose up -d` |
| Compose 停止 | `docker compose down` |
| 磁盘使用情况 | `docker system df` |
| 清理悬空资源 | `docker image prune && docker container prune` |
## 操作流程
### 1. 确定操作域
判断请求属于哪个领域:
- **容器生命周期** → run、stop、start、restart、rm、pause/unpause
- **容器交互** → exec、cp、logs、inspect、stats
- **镜像管理** → build、pull、push、tag、rmi、save/load
- **Docker Compose** → up、down、ps、logs、exec、build、config
- **卷与网络** → create、inspect、rm、prune、connect
- **故障排查** → 日志分析、退出码、资源问题
### 2. 容器操作
**运行新容器:**
```bash
# 后台服务,带端口映射
docker run -d --name web -p 8080:80 nginx
# 带环境变量
docker run -d -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=mydb --name db postgres:16
# 带持久化数据(命名卷)
docker run -d -v pgdata:/var/lib/postgresql/data --name db postgres:16
# 开发环境(绑定挂载源码)
docker run -d -v $(pwd)/src:/app/src -p 3000:3000 --name dev my-app
# 交互式调试(退出后自动删除)
docker run -it --rm ubuntu:22.04 /bin/bash
# 带资源限制和重启策略
docker run -d --memory=512m --cpus=1.5 --restart=unless-stopped --name app my-app
```
关键参数:`-d` 后台运行,`-it` 交互式+tty`--rm` 自动删除,`-p` 端口(宿主机:容器),`-e` 环境变量,`-v` 卷,`--name` 名称,`--restart` 重启策略。
**管理运行中的容器:**
```bash
docker ps # 运行中的容器
docker ps -a # 所有容器(包括已停止的)
docker stop NAME # 优雅停止
docker start NAME # 启动已停止的容器
docker restart NAME # 停止并重启
docker rm NAME # 删除已停止的容器
docker rm -f NAME # 强制删除运行中的容器
docker container prune # 删除所有已停止的容器
```
**与容器交互:**
```bash
docker exec -it NAME /bin/sh # Shell 访问(如可用则使用 /bin/bash)
docker exec NAME env # 查看环境变量
docker exec -u root NAME apt update # 以指定用户运行
docker logs --tail 100 -f NAME # 跟踪最后 100 行日志
docker logs --since 2h NAME # 最近 2 小时的日志
docker cp NAME:/path/file ./local # 从容器复制文件
docker cp ./file NAME:/path/ # 向容器复制文件
docker inspect NAME # 完整容器详情(JSON
docker stats --no-stream # 资源使用快照
docker top NAME # 运行中的进程
```
### 3. 镜像管理
```bash
# 构建
docker build -t my-app:latest .
docker build -t my-app:prod -f Dockerfile.prod .
docker build --no-cache -t my-app . # 全量重新构建
DOCKER_BUILDKIT=1 docker build -t my-app . # 使用 BuildKit 加速
# 拉取与推送
docker pull node:20-alpine
docker login ghcr.io
docker tag my-app:latest registry/my-app:v1.0
docker push registry/my-app:v1.0
# 检查
docker images # 列出本地镜像
docker history IMAGE # 查看层信息
docker inspect IMAGE # 完整详情
# 清理
docker image prune # 删除悬空(未标记)镜像
docker image prune -a # 删除所有未使用镜像(谨慎!)
docker image prune -a --filter "until=168h" # 删除 7 天前未使用的镜像
```
### 4. Docker Compose
```bash
# 启动/停止
docker compose up -d # 后台启动所有服务
docker compose up -d --build # 启动前重新构建镜像
docker compose down # 停止并删除容器
docker compose down -v # 同时删除卷(会销毁数据)
# 监控
docker compose ps # 列出服务
docker compose logs -f api # 跟踪指定服务的日志
docker compose logs --tail 50 # 所有服务最后 50 行日志
# 交互
docker compose exec api /bin/sh # 进入运行中服务的 Shell
docker compose run --rm api npm test # 一次性命令(新容器)
docker compose restart api # 重启指定服务
# 验证
docker compose config # 验证并查看解析后的配置
```
**最简 compose.yml 示例:**
```yaml
services:
api:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
depends_on:
db:
condition: service_healthy
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pgdata:
```
### 5. 卷与网络
```bash
# 卷
docker volume ls # 列出卷
docker volume create mydata # 创建命名卷
docker volume inspect mydata # 详情(挂载点等)
docker volume rm mydata # 删除(使用中则失败)
docker volume prune # 删除未使用的卷
# 网络
docker network ls # 列出网络
docker network create mynet # 创建桥接网络
docker network inspect mynet # 详情(已连接的容器)
docker network connect mynet NAME # 将容器连接到网络
docker network disconnect mynet NAME # 断开容器连接
docker network rm mynet # 删除网络
docker network prune # 删除未使用的网络
```
### 6. 磁盘使用与清理
清理前始终先进行诊断:
```bash
# 检查空间占用
docker system df # 摘要
docker system df -v # 详细分解
# 针对性清理(安全)
docker container prune # 已停止的容器
docker image prune # 悬空镜像
docker volume prune # 未使用的卷
docker network prune # 未使用的网络
# 激进清理(请先与用户确认!)
docker system prune # 容器 + 镜像 + 网络
docker system prune -a # 同时包含未使用镜像
docker system prune -a --volumes # 全部清除——包括命名卷
```
**警告:** 未经用户确认,切勿运行 `docker system prune -a --volumes`。此命令会删除可能包含重要数据的命名卷。
## 常见问题
| 问题 | 原因 | 解决方法 |
|---------|-------|-----|
| 容器立即退出 | 主进程结束或崩溃 | 检查 `docker logs NAME`,尝试 `docker run -it --entrypoint /bin/sh IMAGE` |
| "port is already allocated" | 该端口已被其他进程占用 | 使用 `docker ps``lsof -i :PORT` 查找 |
| "no space left on device" | Docker 磁盘已满 | 执行 `docker system df` 后针对性清理 |
| 无法连接到容器 | 容器内应用绑定到 127.0.0.1 | 应用须绑定到 `0.0.0.0`,检查 `-p` 映射 |
| 卷权限被拒绝 | 宿主机与容器 UID/GID 不匹配 | 使用 `--user $(id -u):$(id -g)` 或修复权限 |
| Compose 服务间无法互通 | 网络错误或服务名称错误 | 服务使用服务名作为主机名,检查 `docker compose config` |
| 构建缓存失效 | Dockerfile 层顺序错误 | 将不常变动的层放在前面(依赖在源码之前) |
| 镜像过大 | 未使用多阶段构建,缺少 .dockerignore | 使用多阶段构建,添加 `.dockerignore` |
## 验证
每次 Docker 操作后,验证结果:
- **容器已启动?** → `docker ps`(检查状态为 "Up"
- **日志无异常?** → `docker logs --tail 20 NAME`(无报错)
- **端口可访问?** → `curl -s http://localhost:PORT``docker port NAME`
- **镜像已构建?** → `docker images | grep TAG`
- **Compose 栈健康?** → `docker compose ps`(所有服务状态为 "running" 或 "healthy"
- **磁盘已释放?** → `docker system df`(对比清理前后)
## Dockerfile 优化建议
审查或创建 Dockerfile 时,建议以下改进:
1. **多阶段构建** — 将构建环境与运行时分离,减小最终镜像体积
2. **层顺序** — 将依赖放在源码之前,避免变更使缓存层失效
3. **合并 RUN 命令** — 减少层数,缩小镜像体积
4. **使用 .dockerignore** — 排除 `node_modules``.git``__pycache__`
5. **固定基础镜像版本** — 使用 `node:20-alpine` 而非 `node:latest`
6. **以非 root 用户运行** — 添加 `USER` 指令以提升安全性
7. **使用 slim/alpine 基础镜像** — 使用 `python:3.12-slim` 而非 `python:3.12`
@@ -0,0 +1,327 @@
---
title: "Pinggy Tunnel — 通过 Pinggy 实现零安装 SSH localhost 隧道"
sidebar_label: "Pinggy Tunnel"
description: "通过 Pinggy 实现零安装 SSH localhost 隧道"
---
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
# Pinggy Tunnel
通过 Pinggy 实现零安装 SSH localhost 隧道。
## Skill 元数据
| | |
|---|---|
| 来源 | 可选 — 使用 `hermes skills install official/devops/pinggy-tunnel` 安装 |
| 路径 | `optional-skills/devops/pinggy-tunnel` |
| 版本 | `0.1.0` |
| 作者 | Teknium (teknium1), Hermes Agent |
| 许可证 | MIT |
| 平台 | linux, macos, windows |
| 标签 | `Pinggy`, `Tunnel`, `Networking`, `SSH`, `Webhook`, `Localhost` |
| 相关 skill | `cloudflared-quick-tunnel`, [`webhook-subscriptions`](/user-guide/skills/bundled/devops/devops-webhook-subscriptions) |
## 参考:完整 SKILL.md
:::info
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 skill 激活时 agent 所看到的指令内容。
:::
# Pinggy Tunnel Skill
使用 Pinggy SSH 反向隧道将本地服务(开发服务器、webhook 接收器、MCP 端点、演示)暴露到公共互联网。无需安装任何守护进程——用户的标准 SSH 客户端连接到 `a.pinggy.io:443`Pinggy 返回一个公共 HTTP/HTTPS URL。
免费套餐:60 分钟隧道,随机子域名,无需注册。Pro 套餐($3/月)需要 token,按需选用。
## 使用时机
- 用户要求"暴露本地服务"、"分享我的开发服务器"、"将此 URL 公开"、"隧道端口 N"、"为 webhook 获取公共 URL"
- 在本地任务期间需要接收 webhook 回调(Stripe、GitHub、Discord、AgentMail
- 与远程方分享一次性 HTTP 演示(MCP 服务器、Ollama/vLLM 端点、仪表盘)
- 主机有 SSH 但没有 `cloudflared` / `ngrok` 二进制文件,安装一个又显得多余
如果主机已配置 `cloudflared`,优先使用 `cloudflared-quick-tunnel` skill——Cloudflare 快速隧道不会在 60 分钟后过期。
## 前提条件
- PATH 中有 `ssh``ssh -V`)。Linux、macOS 和 Windows 10+ 默认自带。无需其他安装。
- 隧道启动前,本地服务已在 `127.0.0.1:<port>` 上监听。Pinggy 会返回 URL,但在本地源服务启动之前访问会返回 502。
可选:
- `PINGGY_TOKEN` 环境变量,用于付费 Pro 功能(持久子域名、自定义域名、多隧道、无 60 分钟限制)。免费套餐无需凭据。
## 快速参考
```bash
# 端口 8000 的普通 HTTP/HTTPS 隧道(免费套餐)
ssh -p 443 -o StrictHostKeyChecking=no -o ServerAliveInterval=30 \
-R0:localhost:8000 free@a.pinggy.io
# TCP 隧道(数据库、原始 SSH 等)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:5432 tcp@a.pinggy.io
# TLS 隧道(Pinggy 无法解密——在源端自带证书)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:443 tls@a.pinggy.io
# Basic auth 认证(b:user:pass
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"b:admin:secret+free@a.pinggy.io"
# Bearer token 认证(k:token
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"k:mysecrettoken+free@a.pinggy.io"
# IP 白名单(w:CIDR
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"w:203.0.113.0/24+free@a.pinggy.io"
# 启用 CORS + 强制 HTTPS 重定向
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 \
"co+x:https+free@a.pinggy.io"
# Pro 套餐(持久 URL,无 60 分钟限制)
ssh -p 443 -o StrictHostKeyChecking=no -R0:localhost:8000 "$PINGGY_TOKEN+a.pinggy.io"
```
## 操作流程——启动隧道并获取 URL
模型应使用 `terminal` 工具。隧道在共享期间必须保持存活,因此以后台进程方式运行,并从 stdout 解析公共 URL。
### 1. 确认本地源服务已启动
```bash
curl -sI http://127.0.0.1:8000/ | head -1
# 期望返回 HTTP/1.x 200(或任何非连接拒绝的响应)
```
如果尚无服务在监听,先启动它(例如 `python3 -m http.server 8000 --bind 127.0.0.1`)。Pinggy 会正常返回 URL,但在本地源服务启动之前用户会看到 502。
### 2. 以后台进程方式启动隧道
使用 `terminal(background=True)` 并将输出捕获到日志文件(Pinggy 在 stdout 打印 URL 后保持连接):
```bash
LOG=/tmp/pinggy-8000.log
nohup ssh -p 443 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-R0:localhost:8000 free@a.pinggy.io \
> "$LOG" 2>&1 &
echo $! > /tmp/pinggy-8000.pid
```
`StrictHostKeyChecking=no` + `UserKnownHostsFile=/dev/null` 跳过首次运行的主机密钥确认提示。`ServerAliveInterval=30` 防止 SSH 会话因空闲 NAT 而被断开。
### 3. 从日志中解析 URL
```bash
sleep 4
grep -oE 'https://[a-z0-9-]+\.[a-z]+\.pinggy\.link' /tmp/pinggy-8000.log | head -1
```
预期输出如下:
```
You are not authenticated.
Your tunnel will expire in 60 minutes.
http://yqycl-98-162-69-48.a.free.pinggy.link
https://yqycl-98-162-69-48.a.free.pinggy.link
```
`https://...pinggy.link` URL 提供给用户。
### 4. 验证
```bash
curl -sI https://<the-url>/ | head -3
# 期望返回 200/302/本地源服务实际返回的状态码
```
如果返回 `502 Bad Gateway`,说明 SSH 会话已建立但本地源服务未在监听——先修复步骤 1。
### 5. 关闭隧道
```bash
kill "$(cat /tmp/pinggy-8000.pid)"
# 或者,如果 pid 文件丢失:
pkill -f 'ssh -p 443 .* free@a\.pinggy\.io'
```
如果有来自 `terminal(background=True)` 的 session_id,优先使用 `process(action='kill', session_id=...)`
## 通过用户名关键字进行访问控制
Pinggy 将控制标志以 `+` 分隔堆叠到 SSH 用户名中。当 `user@host` 参数包含 `+` 时,始终用引号括起整个参数:
| 关键字 | 效果 |
|---------|--------|
| `b:user:pass` | HTTP Basic auth 认证门控 |
| `k:token` | Bearer token 请求头门控(`Authorization: Bearer <token>` |
| `w:CIDR` | IP 白名单(单个 IP 或 CIDR,可重复使用) |
| `co` | 添加 `Access-Control-Allow-Origin: *`CORS |
| `x:https` | 强制 HTTPS——自动将 HTTP 重定向到 HTTPS |
| `a:Name:Value` | 添加请求头 |
| `u:Name:Value` | 更新请求头 |
| `r:Name` | 删除请求头 |
| `qr` | 将 URL 的二维码打印到 stdout(便于移动端分享) |
可自由组合:`"b:admin:secret+co+x:https+free@a.pinggy.io"`
## Web 调试器(可选)
Pinggy 可将入站流量镜像到 `localhost:4300` 以供检查。在 SSH 命令中添加本地转发:
```bash
ssh -p 443 -L4300:localhost:4300 -R0:localhost:8000 free@a.pinggy.io
```
然后在浏览器中打开 `http://localhost:4300`,查看实时请求/响应对。
## 注意事项
- **免费套餐有 60 分钟硬性限制。** SSH 会话在 60 分钟时终止,URL 失效。如需更长时间的共享,使用 `PINGGY_TOKEN`(Pro)或用 shell 循环自动重启(注意免费套餐每次重启 URL 都会变化)。
- **免费套餐 URL 是随机的,重启后会变化。** 不要收藏,不要粘贴到配置文件中。每次都从日志重新解析。
- **同一源 IP 的并发免费隧道限制为一个。** 从同一台机器启动第二个隧道通常会终止第一个。Pro 套餐取消此限制。
- **用户名中的 `+` 必须加引号。** 裸命令 `ssh ... b:admin:secret+free@a.pinggy.io` 在 bash 中可以工作,但在将 `+` 视为特殊字符的 shell 中或以编程方式组装时会出错。始终用双引号括起。
- **不加访问控制标志不要隧道任何敏感内容。** 裸 HTTP 隧道对任何知道 URL 的人都可访问。对非公开服务使用 `b:``k:``w:`
- **`process(action='log')` 可能会遗漏 SSH banner 输出。** Pinggy 打印 URL 后 SSH 会话进入交互模式。始终重定向到日志文件并直接 `grep` 文件——与 `cloudflared-quick-tunnel` 相同的模式。
- **首次运行时的主机密钥提示。** 默认 OpenSSH 配置会要求用户接受 Pinggy 的主机密钥。无人值守运行时始终传入 `-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null`
- **TCP 和 TLS 隧道返回 `<subdomain>.a.pinggy.online:<port>` 对,而非 https URL。** 使用不同的正则表达式解析(`tcp://` 加端口)。不要假设每个 Pinggy 隧道都是 HTTP。
- **Pro 模式需要将 token 作为用户名,而非标志。** 使用 `"$PINGGY_TOKEN+a.pinggy.io"`(无 `free@`)。使用 token 还可以添加 `:persistent` 获得稳定子域名——参见 `pinggy.io/docs/`
## 示例配方
将本地源服务与 Pinggy 隧道结合的复合模式。每个配方均自包含——启动源服务、启动隧道、解析 URL、返回给用户。
### 配方 1——接收 webhook 回调
当外部服务(Stripe、GitHub、Discord、AgentMail 等)需要在本地任务期间 POST 到公开可达的 URL 时使用。
```bash
# 1. 简易捕获服务器:每个请求都追加到 /tmp/webhook-hits.log
cat >/tmp/webhook-server.py <<'PY'
import http.server, json, datetime, pathlib
LOG = pathlib.Path("/tmp/webhook-hits.log")
class H(http.server.BaseHTTPRequestHandler):
def _capture(self):
n = int(self.headers.get("content-length") or 0)
body = self.rfile.read(n).decode("utf-8", "replace") if n else ""
rec = {"t": datetime.datetime.utcnow().isoformat(), "path": self.path,
"method": self.command, "headers": dict(self.headers), "body": body}
with LOG.open("a") as f: f.write(json.dumps(rec) + "\n")
self.send_response(200); self.send_header("content-type","application/json")
self.end_headers(); self.wfile.write(b'{"ok":true}\n')
def do_GET(self): self._capture()
def do_POST(self): self._capture()
def log_message(self,*a,**k): pass
http.server.HTTPServer(("127.0.0.1", 18080), H).serve_forever()
PY
nohup python3 /tmp/webhook-server.py >/tmp/webhook-server.log 2>&1 &
echo $! >/tmp/webhook-server.pid
# 2. 隧道——使用 bearer token 门控,防止无关请求污染捕获日志
nohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 \
-R0:localhost:18080 "k:$(openssl rand -hex 12)+free@a.pinggy.io" \
>/tmp/webhook-pinggy.log 2>&1 &
echo $! >/tmp/webhook-pinggy.pid
sleep 5
URL=$(grep -oE 'https://[a-z0-9-]+\.[a-z]+\.pinggy\.link' /tmp/webhook-pinggy.log | head -1)
echo "Webhook URL: $URL"
# 3. 在 agent 工作期间,监视请求到达
tail -f /tmp/webhook-hits.log
```
`$URL` 提供给需要调用你的服务。关闭:`kill $(cat /tmp/webhook-server.pid) $(cat /tmp/webhook-pinggy.pid)`
### 配方 2——通过 HTTP/SSE 暴露 MCP 服务器
当远程 MCP 客户端(另一台机器上的 Claude Desktop、队友的编辑器等)需要访问本地运行的 MCP 服务器时使用。仅适用于使用 HTTP transport 的 MCP 服务器——stdio 模式的服务器无法被隧道。
```bash
# 1. 以 HTTP 模式启动 MCP 服务器(示例:端口 8765 上的 FastMCP 服务器)
nohup python3 my_mcp_server.py --transport http --port 8765 \
>/tmp/mcp-server.log 2>&1 &
echo $! >/tmp/mcp-server.pid
# 2. 使用 bearer token 建立隧道——MCP 流量不应对互联网开放
TOKEN=$(openssl rand -hex 16)
nohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 \
-R0:localhost:8765 "k:$TOKEN+free@a.pinggy.io" \
>/tmp/mcp-pinggy.log 2>&1 &
echo $! >/tmp/mcp-pinggy.pid
sleep 5
URL=$(grep -oE 'https://[a-z0-9-]+\.[a-z]+\.pinggy\.link' /tmp/mcp-pinggy.log | head -1)
echo "MCP URL: $URL"
echo "Bearer token: $TOKEN"
```
远程客户端使用 `Authorization: Bearer $TOKEN` 连接到 `$URL`。Hermes 原生 MCP 客户端配置:`{"transport": "http", "url": "<URL>", "headers": {"Authorization": "Bearer <TOKEN>"}}`
### 配方 3——暴露本地 LLM 端点(Ollama / vLLM / llama.cpp
与远程调用方(另一个 agent、手机、队友)共享本地模型。Ollama 监听 `:11434`vLLM 和 llama.cpp 通常监听 `:8000`
```bash
# 前提:模型服务器已在 127.0.0.1:11434 上运行(Ollama 默认端口)
TOKEN=$(openssl rand -hex 16)
nohup ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 \
-R0:localhost:11434 "k:$TOKEN+co+free@a.pinggy.io" \
>/tmp/llm-pinggy.log 2>&1 &
echo $! >/tmp/llm-pinggy.pid
sleep 5
URL=$(grep -oE 'https://[a-z0-9-]+\.[a-z]+\.pinggy\.link' /tmp/llm-pinggy.log | head -1)
echo "Endpoint: $URL"
echo "Token: $TOKEN"
# 验证
curl -s "$URL/api/tags" -H "Authorization: Bearer $TOKEN" | head
```
`co` 启用 CORS,使浏览器调用方可以访问端点。纯后端调用方可去掉 `co`。对于兼容 OpenAI 的 vLLM/llama.cpp 端点,调用方使用基础 URL `$URL/v1``Authorization: Bearer $TOKEN`——但请注意 Pinggy 不会修改请求体中的任何内容,因此本地服务器实际上会看到 Pinggy 的 token;本地服务器应配置为忽略认证(它已在 `127.0.0.1` 上),让 Pinggy 负责门控。
### 配方 4——用一次性密码共享开发服务器
最快的"让队友访问我正在运行的应用"模式。随机密码,打印一次,Ctrl-C 后终止。
```bash
PASS=$(openssl rand -base64 12 | tr -d '+/=' | head -c 12)
echo "Dev server password: $PASS"
ssh -p 443 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o ServerAliveInterval=30 \
-R0:localhost:3000 "b:dev:$PASS+co+x:https+free@a.pinggy.io"
# URL 打印到终端。分享 URL + 密码。Ctrl-C 关闭隧道。
```
`b:dev:$PASS` 使用 HTTP Basic auth 对 URL 进行门控。`x:https` 强制 TLS。`co` 为 SPA 前端添加 CORS。
## 验证
```bash
# 端到端:启动一个简单的源服务,建立隧道,访问它,然后关闭
python3 -m http.server 18000 --bind 127.0.0.1 >/tmp/origin.log 2>&1 &
ORIGIN_PID=$!
nohup ssh -p 443 \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
-R0:localhost:18000 free@a.pinggy.io >/tmp/pinggy-verify.log 2>&1 &
SSH_PID=$!
sleep 5
URL=$(grep -oE 'https://[a-z0-9-]+\.[a-z]+\.pinggy\.link' /tmp/pinggy-verify.log | head -1)
echo "URL: $URL"
curl -sI "$URL/" | head -1
kill "$SSH_PID" "$ORIGIN_PID"
```
预期结果:一个 `pinggy.link` URL 以及 curl 返回的 `HTTP/2 200`
@@ -0,0 +1,126 @@
---
title: "Watchers — 使用水印去重轮询 RSS、JSON API 和 GitHub"
sidebar_label: "Watchers"
description: "使用水印去重轮询 RSS、JSON API 和 GitHub"
---
{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
# Watchers
使用水印去重轮询 RSS、JSON API 和 GitHub。
## Skill 元数据
| | |
|---|---|
| 来源 | 可选 — 通过 `hermes skills install official/devops/watchers` 安装 |
| 路径 | `optional-skills/devops/watchers` |
| 版本 | `1.0.0` |
| 作者 | Hermes Agent |
| 许可证 | MIT |
| 平台 | linux, macos |
| 标签 | `cron`, `polling`, `rss`, `github`, `http`, `automation`, `monitoring` |
## 参考:完整 SKILL.md
:::info
以下是 Hermes 在触发此 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
:::
# Watchers
按固定间隔轮询(polling)外部数据源,仅对新条目作出响应。提供三个现成脚本及一个共享水印(watermark)辅助模块;可将其接入 cron 任务,也可从终端临时运行。
## 使用场景
- 用户希望监控 RSS/Atom feed 并在有新条目时收到通知
- 用户希望监控 GitHub 仓库的 issues / pulls / releases / commits
- 用户希望轮询任意 JSON 端点并在有新条目时收到通知
- 用户请求"为 X 创建一个 watcher"或"当 X 变化时通知我"
## 工作原理
一个 watcher 本质上是一个脚本,执行以下操作:
1. 从外部数据源获取数据
2. 与记录已处理 ID 的水印文件进行比对
3. 将新水印写回文件
4. 将新条目打印到 stdout(无变化则不输出)
以下三个脚本均实现了上述逻辑。agent 通过终端工具运行它们——来自 cron 任务、webhook 或交互式对话——并报告新内容。
## 现成脚本
安装 skill 后,三个脚本均位于 `$HERMES_HOME/skills/devops/watchers/scripts/`。每个脚本读取 `WATCHER_STATE_DIR`(默认为 `$HERMES_HOME/watcher-state/`)作为状态文件目录,以 `--name` 参数作为键名。
| 脚本 | 监控对象 | 去重键 |
|---|---|---|
| `watch_rss.py` | RSS 2.0 或 Atom feed URL | `<guid>` / `<id>` |
| `watch_http_json.py` | 任意返回对象列表的 JSON 端点 | 可配置的 id 字段 |
| `watch_github.py` | GitHub 仓库的 issues / pulls / releases / commits | `id` / `sha` |
三个脚本的共同特性:
- 首次运行记录基线——不会重放已有 feed 内容
- 水印为有界 ID 集合(最多 500 条),以限制内存占用
- 输出格式:每条条目为 `## <title>\n<url>\n\n<optional body>`
- 无新内容时 stdout 为空——调用方将此视为静默
- 获取出错时返回非零退出码
## 用法
直接从终端工具运行 watcher
```bash
python $HERMES_HOME/skills/devops/watchers/scripts/watch_rss.py \
--name hn --url https://news.ycombinator.com/rss --max 5
```
监控 GitHub 仓库(在 `~/.hermes/.env` 中设置 `GITHUB_TOKEN` 以避免匿名请求限制 60 次/小时):
```bash
python $HERMES_HOME/skills/devops/watchers/scripts/watch_github.py \
--name hermes-issues --repo NousResearch/hermes-agent --scope issues
```
轮询任意 JSON API
```bash
python $HERMES_HOME/skills/devops/watchers/scripts/watch_http_json.py \
--name api --url https://api.example.com/events \
--id-field event_id --items-path data.events
```
## 接入 cron
向 agent 发送如下 prompt(提示词)以调度 cron 任务:
> 每 15 分钟运行一次 `watch_rss.py --name hn --url https://news.ycombinator.com/rss`。如果有输出,则汇总标题并推送;如果没有输出,则保持静默。
agent 在 cron 任务的 agent 循环中通过终端工具调用脚本,无需修改 cron 内置的 `--script` 标志。
## 状态文件
每个 watcher 将状态写入 `$HERMES_HOME/watcher-state/<name>.json`。查看状态:
```bash
cat $HERMES_HOME/watcher-state/hn.json
```
强制重放(下次运行视为首次轮询):
```bash
rm $HERMES_HOME/watcher-state/hn.json
```
## 自定义 watcher
三个脚本使用相同的模板:加载水印、获取数据、差异比对、保存、输出。`scripts/_watermark.py` 是共享辅助模块;导入它即可免费获得原子写入、有界 ID 集合及首次运行基线功能。参考任意一个脚本,即可了解所需的样板代码有多少。
## 常见问题
1. **每次 tick 都打印"无新条目"的标题。** 调用方依赖 stdout 为空来判断静默。若在空 delta 时打印任何内容,将导致频道被刷屏。已提供的脚本已处理此问题;自定义脚本也必须如此。
2. **期望首次运行就输出条目。** 首次运行只记录基线,不会输出内容。如需初始摘要,可在首次运行后删除状态文件,或在自定义脚本中添加 `--prime-with-latest N` 标志。
3. **水印无限增长。** 共享辅助模块上限为 500 个 ID。对于高频更新的 feed 可适当提高;在存储受限的文件系统上可适当降低。
4. **状态目录位于 agent 沙箱无法写入的位置。** `$HERMES_HOME/watcher-state/` 始终可写。Docker/Modal 后端可能无法访问任意宿主机路径。