npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@guangnao/agent-hub

v1.1.5

Published

Pool subscription-authorized agent nodes behind one OpenAI/Anthropic-compatible /v1 endpoint. Star topology: a central hub + outbound-connected worker nodes, each running a local subscription-auth proxy against its own claude/codex login.

Readme

@guangnao/agent-hub

把多台已授权 claude / codex 的机器聚合成一个 OpenAI / Anthropic 兼容的 /v1 端点。 /v1 任何 OpenAI/Anthropic 客户端指过来即用。

星型拓扑(不是网状 P2P):一个中心 hub + 若干出站连上来的工作节点。每个节点在本机跑一个轻量本地代理、读该机的 claude/codex 订阅登录、字节级转发(Claude 走原生 /v1/messages、保留原生 tool_use)。订阅凭证永不离开节点,只回传结果。

客户端 ──/v1(OpenAI+Anthropic)──▶ hub ──wss──▶ 节点A / 节点B / 节点C …
                                   调度            (各自的 claude/codex 订阅)

⚠️ 合规:把多个个人订阅池化对外,很可能违反 Anthropic/OpenAI 的个人使用条款(封号风险)。自用集群风险低、对外服务风险高 —— 自行斟酌。 🔒 安全:hub 能支配所有节点的额度 —— 生产务必设 AGENT_HUB_API_KEY(客户端)+ AGENT_HUB_NODE_TOKEN(节点),并用防火墙/安全组收紧端口。


安装

npm i -g @guangnao/agent-hub       # 得到 agent-hub 命令

服务器上免 sudo 全局安装(EACCES)

共享机(Amazon Linux 2023 / Debian …)上 Node 的全局目录归 root,npm i -gEACCES … mkdir '/usr/lib/node_modules/@guangnao'这没法由包自动修复 —— 权限错误发生在任何包脚本运行之前,且包不该擅自改你的 npm/shell 配置。装 @guangnao/agent-hub 之前先跑一次下面这段(幂等、可重复跑、不会卡),把全局前缀挪到家目录,之后正常 npm i -g 即可:

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
grep -q '.npm-global/bin' ~/.bashrc || echo 'export PATH=$HOME/.npm-global/bin:$PATH' >> ~/.bashrc
export PATH=$HOME/.npm-global/bin:$PATH      # 当前 shell 立即生效;~/.bashrc 覆盖新开的 shell
npm i -g @guangnao/agent-hub                 # 从此免 sudo

跑过这段后,agent-hub start 缺 pm2 时的自动 npm i -g pm2 也会装进 ~/.npm-global,同样免 sudo、不卡。 替代:sudo npm i -g @guangnao/agent-hub(装成 root),或用 nvm/fnm(其全局目录本就在你名下)。

要求 Node ≥ 20.12

快速开始

1) 起中心 hub(放服务器)。 生产用 start 挂到 pm2(后台、关终端不停、崩溃自拉起):

PORT=8790  HOST=0.0.0.0  agent-hub start        # 不带 AGENT_HUB_API_KEY 时自动生成并落盘
# → pm2 启动 name=agent-hub;就绪后【完整打印 API key】,方便复制:
#     API key (generated + saved to ~/.agent-hub/config.json):
#       sk-…(48 hex)
agent-hub stop        # 停止并从 pm2 删除
agent-hub serve       # 前台运行(容器/调试用,不经 pm2)

API key:start 未设 AGENT_HUB_API_KEY 时自动生成 sk-… 并存到 ~/.agent-hub/config.json(AGENT_HUB_CONFIG 改路径,权限 0600),下次启动不变、每次都完整打印。设了 AGENT_HUB_API_KEY 则以环境变量为准(不落盘)。serve/state 同样按 env > 持久化解析,所以本机 agent-hub state 免手动带 key。要换一把:agent-hub new apikey 生成新 key 并落盘替换旧的——运行中的 hub 不会自动生效,重启才应用(agent-hub stop && agent-hub start)。 服务器健壮性:家目录缺失/只读也不会卡 —— 写入按 AGENT_HUB_CONFIG → ~/.agent-hub → $TMPDIR/agent-hub 逐个降级,全失败则只警告不报错(key 本次仍可用,按提示设 AGENT_HUB_API_KEY 或可写的 AGENT_HUB_CONFIG 即可固定)。 start 会在缺 pm2 时自动 npm i -g pm2;其余环境变量(PORT/HOST/AGENT_HUB_NODE_TOKEN/AGENT_HUB_NODE_RPM)由 pm2 从当前 shell 继承。

查看各节点统计(名称/模型数/容量/在途/近 1min 用量/首字节延迟/冷却):

AGENT_HUB_API_KEY=sk-xxx  agent-hub state http://<hub-ip>:8790     # 缺省读 AGENT_HUB_URL,再缺省 127.0.0.1:8790

2) 起一个节点(放已授权 claude/codex 的机器)。

agent-hub node http://<hub-ip>:8790                 # 前台常驻;托给 pm2/systemd 等你自己的进程管理即可开机自启
AGENT_HUB_NODE_TOKEN=node-secret  AGENT_HUB_NODE_NAME=my-node  agent-hub node http://<hub-ip>:8790

凭证不离机——节点只读本机的 claude/codex 登录态,向 hub 只回传结果。任何客户端工具都可以在自己的启动流程里调用这条命令,实现"检测到本机有可用订阅就自动接入"。

3) 客户端接入。任意 OpenAI/Anthropic 客户端指向 hub 的 /v1:

# OpenAI 兼容
curl http://<hub-ip>:8790/v1/chat/completions \
  -H 'authorization: Bearer sk-xxx' -H 'content-type: application/json' \
  -d '{"model":"gpt-5-codex","messages":[{"role":"user","content":"hi"}],"stream":true}'

# Anthropic 兼容(原生 tool_use)
curl http://<hub-ip>:8790/v1/messages \
  -H 'x-api-key: sk-xxx' -H 'anthropic-version: 2023-06-01' -H 'content-type: application/json' \
  -d '{"model":"claude-sonnet-4-5","max_tokens":256,"stream":true,"messages":[{"role":"user","content":"hi"}]}'

# 全池模型目录
curl http://<hub-ip>:8790/v1/models -H 'authorization: Bearer sk-xxx'

端点(hub)

鉴权范围:只有 /v1/*(会消耗某个节点 subscription 额度的面)受 AGENT_HUB_API_KEY 保护;/health/state/metrics 是纯运维可见性、不设 key(和 Prometheus 抓取端点同一惯例)——对外暴露的话请靠防火墙/安全组收紧,别指望 key。

| 方法 · 路径 | 说明 | |---|---| | POST /v1/messages | Anthropic 面 → 有该模型的节点(Claude 原生透传)·需 key | | POST /v1/chat/completions | OpenAI 面 ·需 key | | POST /v1/responses | OpenAI Responses 面(Codex 原生)·需 key | | GET /v1/models | 全池模型并集({object:'list',data:[…]}需 key | | GET /health | {status, nodes, models, inflight} | | GET /state | 逐节点统计:{totals, nodes:[{id,name,models,capacity,inflight,used1m,cooldownMs,ttfbMs}]} —— agent-hub state 用它 | | GET /metrics | Prometheus 文本(agent_p2p_nodes / models / inflight / nodes_cooldown / jobs_{dispatched,served,failed,ratelimited}_total) |

调度(公平优先 → 合规 → 速度):byModel 倒排索引取"有该模型"的节点后,按容量归一化的近 60s 用量最少者派发 —— 均衡摊派,绝不过度消耗同一节点的订阅额度;平手时看在途数、再看首字节延迟(轻微偏好快节点)。合规护栏:可选每节点每分钟配额上限(AGENT_HUB_NODE_RPM)在触限前就避让;节点上游返回 429/529 → 冷却退避(15s 起翻倍、封顶 5min)暂时移出轮转,成功后恢复。若节点识别出这是账号会话/用量上限(小时级重置,不是瞬时限流)会带上真实的 Retry-After,冷却时长按它来、不再被 5 分钟封顶——避免账号明明还没恢复,5 分钟一到又把它派出去撞一次。跳过满载(inflight ≥ capacity 背压);匹配节点全忙/限流 → 503(可重试);目录未命中回退任意节点(本地代理真校验)。客户端断开 → 通知节点取消;节点掉线 → 挂起请求回 502。

规模化(单进程可撑数千节点):倒排索引使选节点为 O(该模型节点数) 而非全表扫;/v1/models 直接读索引键,不每请求重算并集;单一心跳巡检(ws 原生 ping,死连 terminate)取代"每连接一个定时器";节点上下线超过 50 个后转为 5s 聚合日志(免刷屏)。再往上(数万节点)→ 起多实例 hub 挂 L4 负载均衡、节点/客户端一起打散(无状态分片,天然容灾);仅当需"跨实例全局最优选节点"才引入 Redis 共享注册表。

账号池规模建议:每个账号(节点)的订阅本身有硬上限——Claude/Codex 的会话额度通常是小时级滚动窗口,一旦某个账号打满,在它重置前这个账号完全不可用,跟 hub/调度逻辑无关,加节点数、调参数都绕不开这一点。池子里只有一个账号时,这个账号一打满,/v1/* 就会开始返回 503 all matching nodes are busy or rate-limited——不是 bug,是池子里真的没有可用账号了。实用建议:

  • 账号数 ≥ 预期峰值并发 + 冗余:至少备 2 个账号起步,高峰期负载越高、越该多备几个——某个账号打满时,其余账号能顶上,请求方基本无感。
  • 主动限速优于被动冷却:给每个节点设 AGENT_HUB_NODE_RPM,值设成略低于账号订阅的真实速率上限——在真正撞上账号级会话上限之前就提前避让,而不是等打满了再冷却等重置。
  • 观察 agent-hub stateCOOLDOWN 列——如果频繁看到某个节点冷却时长是几十分钟到几小时级(而不是十几秒到几分钟),说明它在被真实打满,不是偶发限流,该考虑给它设更低的 AGENT_HUB_NODE_RPM,或者往池子里再加账号。

配置(环境变量)

hub(agent-hub serve):

| 变量 | 默认 | 说明 | |---|---|---| | HOST / PORT | 0.0.0.0 / 8790 | 绑定地址 / 端口 | | AGENT_HUB_API_KEY | 自动生成 | 客户端鉴权(x-api-key / Bearer)。start 未设时自动生成并存 ~/.agent-hub/config.json,下次不变;serve 直跑未设且无持久化 = 开放 | | AGENT_HUB_NODE_TOKEN | (空) | 节点注册口令;空 = 任意节点可注册 | | AGENT_HUB_NODE_RPM | 0(不限) | 每节点每分钟派发上限(合规护栏);设成略低于订阅真实限额,触限前即避让 | | AGENT_HUB_JOB_TIMEOUT_MS | 1800000 | 单 job 硬超时兜底:节点始终不回该 job → 巡检回收 | | AGENT_HUB_UNHEALTHY_MS | 5000 | 节点报错后的降级窗口,期间避开调度直到一次成功 | | AGENT_HUB_LOG_JSON | 关闭 | 结构化日志:1 = 每行 JSON(便于日志聚合);默认人类可读 |

节点(agent-hub node <hubUrl>):

| 变量 | 默认 | 说明 | |---|---|---| | AGENT_HUB_URL | (无) | node 子命令缺省的 <hubUrl>,免每次都写 | | AGENT_HUB_NODE_TOKEN | (空) | 必须与 hub 一致(hub 设了才需要) | | AGENT_HUB_NODE_NAME | 主机名 | 节点显示名 | | AGENT_HUB_IDLE_TIMEOUT_MS | 120000 | 单 job 空闲超时(首字节前 / 流中途无字节达到此值 → 判上游挂起,abort 回 504 释放容量) | | AGENT_HUB_MODEL_REFRESH_MS | 300000 | 模型目录定期重拉周期;订阅换档/重新登录后免重连即可刷新 |

凭证来源(节点本机):Claude 读 ~/.claude 登录或 CLAUDE_CODE_OAUTH_TOKEN;Codex 读 ~/.codex/auth.json(codex login)。

通信 / 可靠性

节点主动出站 wss 长连到 hub(NAT/防火墙友好,只需出站),一条连接多路复用多个 job(按 id 关联),响应分块 base64 回传(无跨块截断)。心跳保活、断线指数退避重连;job 有取消/掉线兜底。

编程式用法

@guangnao/agent-hub 除了 CLI,也是一个包:createHub/startNode 都是普通函数,可以直接 import 进你自己的工具——中心和节点各自都能这么用,不一定要经过 agent-hub 命令行。

起中心(createHub)

等价于 agent-hub serve,但配置项直接传参、不走环境变量;返回一个 node:http Server

import { createHub } from '@guangnao/agent-hub';

const hub = createHub({ port: 8790, apiKey: 'sk-xxx', nodeToken: 'node-secret' });
// hub.close() 即可关闭(会先停收新连接、清定时器)

HubOptions(全部可选):

| 字段 | 说明 | |---|---| | port / host | 缺省 8790 / 0.0.0.0 | | apiKey | 客户端鉴权;''/缺省 = 开放 | | nodeToken | 节点注册口令;''/缺省 = 任意节点可注册 | | nodeRpm | 每节点每分钟派发上限(合规护栏);缺省不限 | | jobMaxMs | 单 job 硬超时兜底;缺省 30min | | unhealthyMs | 节点报错后的降级窗口;缺省 5s | | logJson | true → 结构化 JSON 日志;缺省人类可读 | | log | 自定义日志 sink((line: string) => void);缺省写 stdout |

起一个节点(startNode)——把"接入池子"嵌进你自己的工具

这是把 agent-hub 当开发包用的主要场景:不用另开一个 agent-hub node 子进程,直接在你自己的程序里 import { startNode } 调用,服务在启动时检测到本机有可用的 claude/codex 订阅,省掉一层子进程管理,状态、日志、优雅退出都由调用方掌控。

import { startNode } from '@guangnao/agent-hub';

const ac = new AbortController();
await startNode({
  hubUrl: 'http://hub:8790',
  token: 'node-secret',
  onlyIfCredentialed: true,   // 本机没有可用的 claude/codex 凭证 → 静默不接入,直接 resolve(适合"能接就接、不能就算了"的自动化)
  status: false,              // 关掉终端实时状态行(嵌入到自己的 UI 里时通常想自己控制输出)
  log: (line) => myLogger.info(line),   // 缺省写 stderr;传自己的 logger 就接管
  signal: ac.signal,          // 传了才会在 abort 时 resolve——不传则常驻直到进程退出
});
// ac.abort() → 优雅下线(关 ws 长连 + 本地代理端口),Promise 随之 resolve

NodeOptions:

| 字段 | 说明 | |---|---| | hubUrl | 必填,hub 地址 | | token | 节点注册口令;需与 hub 的 nodeToken 一致 | | name | 节点显示名;缺省主机名 | | onlyIfCredentialed | true 时:本机拉不出任何 claude/codex 模型 → 不注册、直接 resolve(不报错、不重试) | | status | 是否在 stderr 画实时状态行;缺省按 process.stderr.isTTY | | log | 自定义日志回调;缺省写 stderr | | signal | 传入后,abort() 触发优雅停止(关 ws + 本地代理)并 resolve;不传则 startNode 常驻不返回 |

凭证读取(onlyIfCredentialed/上报模型目录都靠它):Claude 走 ~/.claude 登录或 CLAUDE_CODE_OAUTH_TOKEN;Codex 走 ~/.codex/auth.json(codex login)——和节点 CLI 的凭证来源完全一致,因为底层是同一份实现。

许可

MIT。