njucliCAUTION
南京大学校园服务 CLI 与 AI Skills
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://github.com/MarcWebber/njucli/actions/workflows/ci.yml) [](https://nodejs.org/) [](LICENSE) [](https://github.com/MarcWebber/njucli/stargazers) [](https://github.com/MarcWebber/njucli/forks)
南京大学校园服务工具,让 AI 帮你查课表、收邮件、管理云盘和处理校园事务。
安装
需要 Node.js 20+、Git、curl 和 Bash。网页登录及页面操作使用本机浏览器,运行前提见认证 Skill。
curl -fsSL https://raw.githubusercontent.com/MarcWebber/njucli/main/scripts/install.sh | bash
同时安装全局 njucli 和 Skills。Skill 默认注册到 ${CODEX_HOME:-~/.codex}/skills/,可通过 NJUCLI_SKILLS_DIR 指定其他客户端的目录。使用 NJUCLI_INSTALL_PREFIX 指定 CLI 安装前缀时,将其 bin 目录加入 PATH。
升级:
njucli upgrade
只安装一个 Skill
例如,只安装教务与办事大厅:
curl -fsSL https://raw.githubusercontent.com/MarcWebber/njucli/main/scripts/install.sh | bash -s -- --skill ehall
将 ehall 换成 se、box、mail 等名称即可安装其他 Skill。再次运行同一命令即可更新。
现有 Skills
点击名称查看使用方法。
e48161967243OBSERVED · 2026-10-11Host compatibility
What the documentation claims. We have not run a compatibility test.
| Host | Status | Notes |
|---|---|---|
| codex | mentioned | |
| cursor | mentioned |
What it tells the agent
The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.
--- name: njucli-auth description: 登录南京大学统一身份认证、保存本地凭据、查询与维护会话状态、协助处理登录滑块验证。在涉及校园登录或会话失效时使用。 --- # 统一身份认证 以下命令在本 Skill 目录运行;扫码由本人完成。 ## 运行前提 已保存会话的查询通过 HTTP 执行,网页登录及页面操作按需启动本机浏览器。当前浏览器入口使用 Playwright 的 `chrome` 通道。后台保活由 Node.js 启动独立 CLI 进程,在 Unix 系统上使用相同的命令和 XDG 目录规则。Windows 的后台进程行为待验证。 ## 登录与状态 通过 JSON 文件导入统一认证账号与密码(内容包含 `username` 和 `password`): ```bash node scripts/run.mjs auth login --credentials /path/to/auth.json node scripts/run.mjs auth status sso --format json node scripts/run.mjs auth login box node scripts/run.mjs account use ACCOUNT ``` 省略登录目标时默认使用 `sso`。也支持单独登录 `box`、`selection`、`ehall`、`timetable`、`se`、`tex`、`sports`、`youth`、`table`、`vpn`、`opac` 等站点。 `account use` 或环境变量 `NJUCLI_ACCOUNT` 用于选择本地账号。业务命令会按需恢复登录,`auth status` 返回 `valid` 表示会话可用。CLI 使用专用浏览器与账号目录,普通浏览器中的登录由该浏览器独立保存。 凭据和 Cookie 保存在 `~/.config/njucli/accounts/<账号>/`,可通过 `XDG_CONFIG_HOME` 设置配置根目录,文件权限为 0600。浏览器资料目录由 `XDG_DATA_HOME` 设置数据根目录。同一账号的调用通过进程锁串行读写 Cookie。 ## 会话维护 ```bash node scripts/run.mjs auth maintain --format json ``` 该命令检查统一认证与 EHall 会话,并保存更新的 Cookie。会话有效时返回 `kept-alive`,用已存凭据恢复成功后返回 `restored`。 学校决定会话的闲置期限和最长有效期;到期后使用已存凭据重新登录。用户要求持续维护时,启动下方后台进程,并按实际闲置期限设置间隔。 ## 后台保活 先保存统一认证凭据,再启动常驻 CLI 进程,持续维护当前账号: ```bash node scripts/run.mjs auth daemon start node scripts/run.mjs auth daemon status --format json node scripts/run.mjs auth daemon stop ``` 启动后立即维护一次,之后每轮结束后等待 600 秒。使用 `start --interval 300` 可设为五分钟;间隔支持 1–2147483 秒的整数。调整间隔时先 `stop` 再 `start`。通过构建后的 CLI 或本 Skill 的 `scripts/run.mjs` 启动。 进程固定启动时的账号与配置目录,每轮复用账号 Cookie 和进程锁,退出终端后继续运行。系统重启或进程退出后通过 `start` 恢复。普通网络失败后在下个周期再维护;学校拒绝凭据、凭据缺失或要求本人操作时结束进程,处理原因后重新启动。后台保活停止时,业务命令仍会按需检查和恢复会话。 `status` 返回 `running/pid`(进程状态)、`intervalSeconds`(维护间隔)、`lastSuccess`(最近成功维护)和 `lastResult`(最近输出)。账号目录下的 `auth-daemon/process.json` 与 `auth-daemon/output.log` 保存进程记录和脱敏日志,权限为 0600。默认路径为 `~/.config/njucli/accounts/<账号>/auth-daemon/`;设置 `XDG_CONFIG_HOME` 后位于该根目录的 `njucli/accounts/<账号>/auth-daemon/`。 `stop` 等待当前维护结束后清理进程记录。退出账号、删除账号或升级 CLI 前先停止后台进程;升级后重新启动,使用新的 CLI 入口。 遇到登录错误时: - `AUTH_REJECTED`:按学校返回的原因检查账号状态和凭据。 - `AUTH_CHALLENGE_FAILED`:滑块验证尝试超限,请重新运行或使用下方滑块脚本。 - `USER_ACTION_REQUIRED`:需要手机扫码或其他人工操作,请在官方页面完成。 - `AUTH_RESTORE_FAILED`:自动恢复会话失败,请检查网络或重新登录。 ## 滑块验证辅助 统一认证已内置滑块识别。若多次验证失败,可在交互式终端运行辅助脚本: ```bash node scripts/login.mjs ``` 输入 `shot` 获取截图,再输入 `drag x y dx` 拖动滑块。`x/y` 是滑块按钮中心,`dx` 是向右移动的距离,均按当前截图的 CSS 像素计算。验证成功后保存会话;完成后删除临时截图 `njucli-slider.png`。
Trust audit
CAUTIONgrade C · trust 72/100 Install with care. The audit found things worth knowing before you trust its output.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | WARN |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | PASS |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (5 observation(s))
- Network
- declared (6 observation(s))
- Shell
- none-observed
- Dependencies
- not all pinned
- Secrets in source
- found
Findings (20)
const response = await fetch(`http://127.0.0.1:${worker.port}/${action}`, {const uploadLink = await client.uploadLink("repo", "/materials", { password: "private-upload-password" });const credentials = { username: "sso-student", password: "synthetic-sso-secret" };await writeJsonFile(started.processPath, { ...worker, pid: process.pid, token: "synthetic-wrong-token" });return generationError ? { errcode: 1 } : { errcode: "0", data: { passwd: "synthetic-mail-secret" } };await writeJsonFile(input, { address: "[email protected]", password: "synthetic-mail-secret" });return createHash("md5").update(payload, "utf8").digest("hex");import { createRuntime } from '../../../src/app/runtime.js';import { runSkill } from '../../../src/app/skill.js';export { withBrowserSession } from '../../../src/auth/browser-session.js';export { createAuthServices } from '../../../src/auth/service.js';export { createRuntime } from '../../../src/app/runtime.js';const origin = `http://127.0.0.1:${server.address().port}`;const origin = `http://127.0.0.1:${server.address().port}`;const origin = `http://127.0.0.1:${server.address().port}`;const rejected = await fetch(`http://127.0.0.1:${worker.port}/stop`, { method: "POST" });@modelcontextprotocol/sdk, cheerio, commander, imapflow, mailparser, playwright-core, zod, @types/mailparser
curl -fsSL https://raw.githubusercontent.com/MarcWebber/njucli/main/scripts/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/MarcWebber/njucli/main/scripts/install.sh | bash -s -- --skill ehall
curl -fsSL https://raw.githubusercontent.com/MarcWebber/njucli/main/scripts/install.sh | bash -s -- --skill se
Gates applied: no_behavioural_pass.
e48161967243full audit observations/trust-audit/skill/marcwebber__njucli.json · Report an issue / request a re-scanAudit history
Every audit this skill has had.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-11 | e48161967243 | CAUTION | C | 72 | first audit |
Questions
What does the njucli skill do?
南京大学校园服务 CLI 与 AI Skills
Is njucli safe to install?
With care. The audit graded it C (72/100) and found 20 things worth knowing before you trust this skill, listed below with the exact line each was found on.
What can njucli access on my machine?
The audit observed that it reaches the network and reads or writes files. Each of those is consistent with what it says it does. Secrets in the source: found — see the findings.
Which assistants does njucli work with?
Its documentation mentions codex and cursor. That is what the text claims, not a compatibility test we ran.
How current is this page?
The grade is for one exact copy of the source (e48161967243), read on 2026-10-11. The repository is watched, and a new audit runs when it changes — this is the first audit.