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

@kernel-sig/console

v0.1.1

Published

openEuler Kernel SIG 的 PR/Issue 管理平台:一条命令在本机起一整套实例

Readme

Kernel SIG Console

openEuler Kernel SIG 的本地自托管协作平台,用于管理 AtomGit 上的 PR 与 Issue。

为什么需要它

openEuler 内核仓库当前有 1000+ 个开放的 PR,评审状态由 lgtm-* / approved / ci_* 标签承载,没有统一视图。Maintainer 难以快速识别优先级、统计评审 SLA、 发现被淹没的重要 PR。

本平台把这些信息结构化,并提供 AI 辅助分析。

功能

| 模块 | 说明 | 状态 | |------|------|------| | 认证与权限 | 五级 RBAC(观察者/评审者/提交者/维护者/管理员),审计留痕 | 已实现 | | PR 管理 | 门禁阶段筛选、标题/编号检索、分支与排序、详情含提交/文件 diff/评审时间线 | 已实现 | | Issue 管理 | 按 AtomGit 原生类型与优先级筛选、状态着色 | 已实现 | | 评审跟踪 | 从评论解析评审事件,归属评审人工作量;合并门禁四段推导 | 已实现 | | 数据同步 | 分层增量同步(列表/详情/评论),幂等,支持 webhook 触发 | 已实现 | | 定时轮询 | ARQ worker 按任务错峰调度:列表 / 详情 / 分类 / 关注项 / AI 补判 | 已实现 | | 统计分析 | 积压时长、合并周期、门禁分布、分支分布、评审人排行 | 已实现 | | 凭据管理 | AES-256-GCM 加密存储、指纹展示、有效性校验 | 已实现 | | 自动分类 | 规则优先、AI 兜底,识别 CVE / Backport / 子系统归属,支持人工指定 | 已实现 | | 关注队列 | 13 条规则收敛成可认领的待办,每条附判定依据 | 已实现 | | AI 对接 | OpenAI 兼容协议、按任务路由模型、类型补判 / 摘要 / 风险审查 / backport 核对 | 已实现 |

实测数据(openeuler/kernel)

平台在真实仓库上验证,以下为某次同步的实际结果:

| 指标 | 数值 | |------|------| | 未合并 PR | 1,133 | | 已合并 PR | 4,000 | | 未关闭 Issue | 2,031 | | 可立即合入 | 179 | | 待评审 | 772 | | 超 30 天未评审 | 457 | | 合并周期中位数 | 2 天 |

「可合入」指 CLA 已签署、CI 通过、有 LGTM 且已关联 Issue —— 在这之前,这些信息散落在上千个 PR 的标签里,无法一眼看出。

关于评审状态的两个反直觉事实

实现过程中通过真实数据确认,与直觉相反,且都会导致维护者看到错误信息:

  1. CI 失败标签是 ci_failed,而非 ci_must_go_failed(实测前者 36 次、后者 1 次)。
  2. approved 不是合入前的前置门禁:200 个 open PR 中 0 个带此标签, 而 200 个已合并 PR 中 199 个带 —— 它是合入时补记的标记。 把它当作前置条件会让「可合入」状态永不可能出现。
  3. 评审人身份在评论里,不在标签里:PR 上用的是整体 lgtm 标签, 具体是谁评审的,记录在人类的 /lgtm 评论中。

自动分类、关注队列与 AI

三者是同一条链路上的三环:规则能判的判定,判不出的交给模型,需要人看的排成待办。

分类:规则优先,AI 兜底,人工最高

规则是确定性的(标题里有 CVE-\d{4}-\d{4,} 就是 CVE),因此先跑规则。 实测 3164 个 open PR/Issue 上规则覆盖率约 54% —— 剩余部分不是规则写少了, 而是内核补丁标题描述的是「改了什么」而非「属于哪一类」。这部分交给模型补判。

三档优先级严格有序,且每条记录都保留判定来源与依据:

| 来源 | 何时写入 | 会被谁覆盖 | |------|----------|-----------| | 规则 | 每次同步后重算 | 规则、AI、人工 | | AI | 规则判不出时补判 | 人工;规则判不出来时不覆盖 | | 人工 | 维护者显式指定 | 只有维护者自己撤销 |

第二条约束不是可选项。规则每 10 分钟全量重算一次;若允许它把 AI 的结论打回 unknown,那条记录下一轮又会被挑去补判 —— 模型会被反复调用同一个对象, 既不收敛也持续计费。

关注队列:只给结论是没有用的

13 条规则覆盖 PR 与 Issue 两侧(评审超期、CI 失败、CVE 未推进、缺签名、 Issue 无人认领……)。每条命中都带证据:等了几天、哪个文件是二进制、 缺几个签名、涉及哪些 CVE。维护者据此可以直接决定下一步动作, 而不是只看到一个「有问题」的标记。

状态是保留而非覆盖的:命中时保留 first_detected_at,不再命中的置 resolved_at 而不删除 —— 「这条挂了多久才被处理」本身就是要看的信息。

AI:唯一按次计费的部分

  • 按任务配模型:分类这类轻任务用便宜模型,代码风险审查才用强模型
  • 内容指纹幂等:输入没变就不重复调用,force=true 才强制重跑
  • 失败不中断:单条上游失败只落状态,不让整轮定时任务停摆; 但未配置模型属于部署问题,直接抛错,不留失败记录污染用量统计
  • Prompt 内嵌领域规则:KABI 兼容性约束、补丁格式要求、backport 核对方法, 而不是让它「通用地评审一段代码」

快速开始

前提只有一个:本机装了 Docker。

npx @kernel-sig/console            # 起一整套实例,首次要构建镜像、几分钟
npx @kernel-sig/console --open      # 顺手打开浏览器

首次运行会自动生成 ~/.kernel-sig/.env(含随机的 KSC_SECRET_KEY)、构建镜像、 起容器,就绪后打印地址。访问 http://localhost:18080 会引导创建管理员账号。

装成全局之后命令短得多,日常用这个:

npm i -g @kernel-sig/console
ksc          # 再次启动,秒级
ksc logs     # 看日志
ksc status   # 看容器状态
ksc down     # 停止;数据留在 docker 卷里,下次启动仍在

新实例默认已纳管 openeuler/kernel。给个 AtomGit token 就开始拉数据:

ksc --token <你的 AtomGit token>

不给也能起,只是没有数据 —— 界面上的仓库卡片会标明「未配置凭据」并指向凭据设置, 之后随时在「设置 → 凭据」里补。

注意:这是在你本机跑一个独立实例,不是连到别人的服务;和已有的实例各有各的 数据库。另外平台的定时同步需要机器常驻,合上笔记本就停了 —— 适合试用与评估, 正式给团队用仍然建议部署到服务器(见下一节)。

从源码部署

服务器上部署走这条,ksc 只是它的封装:

cp .env.example .env
# 生成密钥并写入 .env 的 KSC_SECRET_KEY
openssl rand -hex 32

make up

常用命令

make help        # 查看全部命令
make up          # 启动
make down        # 停止
make logs        # 查看日志
make migrate     # 执行数据库迁移
make test        # 运行测试
make lint        # 静态检查

配置

所有配置通过环境变量提供,见 .env.example。

| 变量 | 说明 | 默认值 | |------|------|--------| | KSC_SECRET_KEY | 凭据加密与 JWT 签名密钥(≥32 字符),必填 | 无 | | DOCKER_REGISTRY | 镜像源前缀 | docker.m.daocloud.io | | PIP_INDEX_URL | 构建时的 PyPI 源 | 清华源 | | KSC_WEB_PORT | Web 访问端口 | 18080 | | KSC_ENVIRONMENT | development / production | production | | KSC_BOOTSTRAP_REPOSITORY | 首次启动自动纳管的仓库(owner/name) | openeuler/kernel | | KSC_ATOMGIT_TOKEN | 首次启动导入成凭据;不填则在界面上添加 | 空 |

端口说明:默认使用 18080 / 18000 / 15432 / 16379, 主动避开常见的 80 / 443 / 3000 / 8000 / 6379,以免与本机既有服务冲突。

镜像源说明:部分网络环境直连 Docker Hub 与 pypi.org 极慢或不可达, 因此默认走国内镜像源。其他网络环境改回官方源即可。

架构

浏览器 → Nginx (:18080) → FastAPI (:8000) → PostgreSQL
                                      ↘
                          ARQ Worker → AtomGit API / LLM
                                      ↘ Valkey(队列)

后端分层为 API / Service / Model / Core,依赖单向:api → services → models, integrations 不依赖任何内部模块,保证领域逻辑能被 worker 与测试独立复用。

worker 与 API 复用同一镜像、只换启动命令。迁移由 API 进程负责执行, worker 等它就绪再接活,避免两个进程同时跑 Alembic。

定时任务节奏

分钟点刻意错开:全部压在整点会让上游在瞬间收到成倍请求, 自己的数据库也会同时承受多个全量重算。

| 任务 | 频率 | 超时 | |------|------|------| | sync_pulls | 每 10 分钟 | 600s | | sync_issues | 每 30 分钟 | 600s | | sync_pull_details | 每 5 分钟(一批 50 个) | 900s | | classify_repository | 每 10 分钟 | 600s | | compute_attention | 每 15 分钟 | 600s | | run_ai_analysis | 每 30 分钟(一批 5 个) | 1800s |

详情同步刻意小批量高频:单次请求量大时上游会限流, 而列表同步必须先跑完 —— 关注项规则读的是它写下的派生列。

安全

  • AtomGit token 与 LLM API Key 使用 AES-256-GCM 加密落库, 密钥由 KSC_SECRET_KEY 经 HKDF-SHA256 派生(不直接复用配置密钥)
  • 界面不回显凭据明文,仅展示指纹
  • 密码使用 Argon2id 哈希
  • 会话令牌存 HttpOnly + SameSite Cookie
  • 所有写操作记入审计日志,凭据类字段自动脱敏

开发

# 仅启动依赖服务
docker compose up -d postgres valkey

# 后端(本机)
cd backend
python3 -m venv .venv
.venv/bin/pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -e ".[dev]"
.venv/bin/uvicorn app.main:app --reload --port 18000

# 前端(本机)
cd frontend && npm install && npm run dev   # http://localhost:15173

验证脚本

除单元测试外,仓库内有三个跑在真实数据 / 真实浏览器上的校验脚本。 单元测试证明代码符合预期,这三个脚本证明系统在真实环境下确实工作。

# 浏览器端到端(100+ 项断言,覆盖全部页面与交互)
# 需要 playwright:pip install playwright && playwright install chromium
python3 scripts/e2e-verify.py

# 分类与关注项:跑在真实数据库上,验证覆盖率与重算幂等
cd backend && KSC_SECRET_KEY=... .venv/bin/python ../scripts/verify-analysis-pipeline.py

# AI 链路:本地桩服务冒充 OpenAI 兼容端点,验证请求头/payload/
# JSON 解析/幂等/失败降级/人工覆盖优先
cd backend && KSC_SECRET_KEY=... .venv/bin/python ../scripts/verify-ai-pipeline.py

后两个脚本读的是本机活实例的数据库,断言不假设环境为空; 它们验证的是数据的性质(覆盖率、幂等、不打回 AI 判定), 这些性质只有数据真实存在时才可验证。

发布到 npm(维护者)

package.json 顶部的 files 是显式白名单,不是可选项。实测 npm 10.9.8 会把 白名单里列出的目录原样整目录收进包 —— frontend/node_modules(290 MB) 就是这么做进去的,.npmignore 拦不住。所以新增构建产物类的文件时,要同步更新这份 名单,不要指望忽略文件。

发布前先看一遍清单,尤其确认里面没有 .env(那是明文密钥):

npm pack --dry-run          # 看清单
npm pack                    # 出 tarball,可先用它本地验一遍
npm publish --access public --otp=<六位码>

name@version 一旦发布就永远不能重用(即使 npm unpublish 也不行), 所以先用 npm exec --package=./kernel-sig-console-0.1.0.tgz -- ksc up 跑通再发。

许可

木兰宽松许可证,第 2 版(Mulan Permissive Software License, Version 2, SPDX 标识符 MulanPSL-2.0)。

Copyright (c) 2026 Xie XiuQi