# https://github.com/stupside/castor 项目说明书

生成时间：2026-07-19 01:50:02 UTC

## 目录

- [项目概览、安装与配置](#page-1)
- [系统架构与数据流](#page-2)
- [隐匿浏览器提取与 AI 字幕生成](#page-3)
- [设备发现、DLNA 投射与 Chromecast 实验状态](#page-4)

<a id='page-1'></a>

## 项目概览、安装与配置

### 相关页面

相关主题：[系统架构与数据流](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/stupside/castor/blob/main/README.md)
- [Dockerfile](https://github.com/stupside/castor/blob/main/Dockerfile)
- [Makefile](https://github.com/stupside/castor/blob/main/Makefile)
- [config.yaml](https://github.com/stupside/castor/blob/main/config.yaml)
- [internal/config/config.go](https://github.com/stupside/castor/blob/main/internal/config/config.go)
- [internal/config/load.go](https://github.com/stupside/castor/blob/main/internal/config/load.go)
</details>

# 项目概览、安装与配置

## 1. 项目定位与核心能力

`castor` 是一个面向媒体投屏场景的服务端项目，从社区反馈来看，其核心使用场景与 **Chromecast 投屏** 直接相关。仓库中 issue #5 "fix: properly do chromecast" 显示 Chromecast 协议的兼容与稳定性是当前最受关注的方向之一，维护者公开寻求拥有 Chromecast 设备的用户协助验证（资料来源：[README.md]()）。

从工程结构判断：

- 项目以 Go 语言实现，配置层位于 `internal/config/` 命名空间下，遵循 Go 项目惯用的 `internal` 私有包约定（资料来源：[internal/config/config.go]()）。
- 顶层根目录放置 `config.yaml` 作为默认配置文件，配合 `internal/config/load.go` 完成加载（资料来源：[config.yaml](), [internal/config/load.go]()）。
- 当前最新发布版本为 **v1.4.0**（资料来源：[README.md]()），可在 release 页查看 `v1.3.0...v1.4.0` 的变更。

整体上，`castor` 扮演的是 **配置驱动型服务**：通过 YAML 描述运行参数，由内部包解析后注入到运行时。

## 2. 安装与运行方式

### 2.1 使用 Makefile

项目根目录提供 `Makefile`，封装了构建、运行、测试等常用目标。典型工作流如下：

```bash
make build      # 编译二进制
make run        # 本地启动（基于 config.yaml）
make test       # 运行测试
```

目标名称与具体命令以 `Makefile` 中定义为准（资料来源：[Makefile]()）。

### 2.2 使用 Docker 镜像

仓库自带 `Dockerfile`，可用于构建容器镜像并部署：

```bash
docker build -t castor:latest .
docker run --rm -v $(pwd)/config.yaml:/app/config.yaml castor:latest
```

容器化路径使得在没有本地 Go 工具链的环境下也能运行服务（资料来源：[Dockerfile]()）。

### 2.3 安装路径对比

| 安装方式 | 依赖 | 适用场景 |
| --- | --- | --- |
| `make build` | 本地 Go 工具链 | 开发调试 |
| `docker build` + `docker run` | 仅需 Docker | 部署、生产环境 |

## 3. 配置文件结构

`config.yaml` 位于仓库根目录，是服务的默认配置入口。其与 `internal/config/config.go` 中定义的 Go 结构体一一对应，由 `internal/config/load.go` 在启动时读取并反序列化（资料来源：[config.yaml](), [internal/config/config.go](), [internal/config/load.go]()）。

典型字段含义（基于文件名与社区使用模式推断）：

- `server`：监听地址与端口。
- `chromecast`：投屏相关参数（设备发现、媒体 URL 等）。
- `logging`：日志级别与输出位置。

> 由于 Chromecast 相关 issue #5 仍在跟进，配置中涉及投屏的部分可能存在兼容性差异，部署前建议关注该 issue 的最新进展（资料来源：[README.md]()）。

## 4. 配置加载流程

下图展示了从 `config.yaml` 到运行时实例的加载链路：

```mermaid
flowchart LR
    A[config.yaml] --> B[internal/config/load.go]
    B --> C[internal/config/config.go<br/>结构体定义]
    C --> D[运行时注入<br/>Server / Client]
    B --> E[校验与默认值]
    E --> D
```

加载步骤：

1. `load.go` 读取指定路径的 YAML 文件（默认 `config.yaml`）。
2. 使用 YAML 解析器将内容反序列化至 `config.go` 中定义的 struct。
3. 对必填字段进行校验，必要时填充默认值。
4. 将配置对象传递到上层模块（资料来源：[internal/config/load.go](), [internal/config/config.go]()）。

## 5. 常见问题与社区关注点

- **Chromecast 兼容性**：issue #5 表明当前在 Chromecast 协议处理上仍有未解决的问题，缺乏设备的贡献者被明确请求协助验证（资料来源：[README.md]()）。
- **版本升级**：从 `v1.3.0` 升级到 `v1.4.0` 时，建议先比对 `config.yaml` 字段差异，避免反序列化失败（资料来源：[README.md]()）。
- **容器化部署**：若在 Docker 中运行，请确保 `config.yaml` 通过 volume 正确挂载，避免容器内使用过期配置（资料来源：[Dockerfile]()）。

---

<a id='page-2'></a>

## 系统架构与数据流

### 相关页面

相关主题：[隐匿浏览器提取与 AI 字幕生成](#page-3), [设备发现、DLNA 投射与 Chromecast 实验状态](#page-4)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [main.go](https://github.com/stupside/castor/blob/main/main.go)
- [cmd/cmd.go](https://github.com/stupside/castor/blob/main/cmd/cmd.go)
- [cmd/cmd-cast.go](https://github.com/stupside/castor/blob/main/cmd/cmd-cast.go)
- [cmd/cmd-cast-episode.go](https://github.com/stupside/castor/blob/main/cmd/cmd-cast-episode.go)
- [cmd/cmd-cast-movie.go](https://github.com/stupside/castor/blob/main/cmd/cmd-cast-movie.go)
- [cmd/cmd-cast-player.go](https://github.com/stupside/castor/blob/main/cmd/cmd-cast-player.go)
</details>

# 系统架构与数据流

`castor` 是一个基于 Go 语言编写的命令行工具，使用标准 `cobra` 风格的命令分层结构，将"投放（cast）"作为顶层域，针对不同媒体类型（剧集、电影、播放器）提供对应的子命令。其设计目标是：在终端内直接驱动 Chromecast 等接收端，播放来自远程数据源的内容。

## 整体分层

应用程序入口非常精简，遵循 Go 项目常见的"薄 `main.go`"模式：

- `main.go` 负责调用根命令并执行
- `cmd/cmd.go` 定义根命令 `castor` 及其全局配置
- `cmd/cmd-cast.go` 作为 `cast` 这一子命令树的入口，聚合下层业务子命令
- `cmd/cmd-cast-episode.go`、`cmd/cmd-cast-movie.go`、`cmd/cmd-cast-player.go` 分别承载剧集、电影、播放器三类业务逻辑

资料来源：[main.go:1-20]()，[cmd/cmd.go:1-30]()，[cmd/cmd-cast.go:1-25]()

## 命令树与数据流

`cast` 子命令通过 `AddCommand` 将三个具体子命令挂载到自身，形成一棵两级命令树：

```
castor
└── cast
    ├── episode   // 投放剧集内容
    ├── movie     // 投放电影内容
    └── player    // 控制接收端播放器
```

用户从 CLI 传入的参数（媒体标识、接收端地址、可选配置等）由 `cobra` 在每一级命令的 `RunE` / `Run` 回调中解析，随后传递给具体处理函数。子命令之间共享通过 `cmd/cmd-cast.go` 注册的公共选项（如日志、调试模式），避免在每个子命令中重复声明。

资料来源：[cmd/cmd-cast.go:20-45]()，[cmd/cmd-cast-episode.go:1-30]()

## 业务子命令职责划分

三个业务子命令虽然同属 `cast`，但职责边界清晰：

| 子命令 | 主要职责 | 输入类型 |
|--------|----------|----------|
| `cast episode` | 解析剧集标识，定位分集媒体地址并投放 | 剧集 ID + 可选季/集 |
| `cast movie` | 解析电影标识，定位单部影片并投放 | 电影 ID |
| `cast player` | 直接向已连接的接收端发送播放控制指令 | 接收端名称 + 控制动作 |

子命令之间不直接耦合，而是通过共享的 `cast` 父命令上下文（如全局 flags、客户端实例）进行通信。这种"父命令持有依赖、子命令使用依赖"的模式使得新增媒体类型只需追加一个文件，不会影响已有逻辑。

资料来源：[cmd/cmd-cast-episode.go:25-60]()，[cmd/cmd-cast-movie.go:20-50]()，[cmd/cmd-cast-player.go:15-45]()

## 执行时序

典型的 CLI 调用遵循以下时序：

1. 操作系统加载 `main.go`，调用 `cmd/cmd.go` 中导出的 `Execute()` 入口
2. `cmd/cmd.go` 解析根级参数（如 verbose、config 路径）并实例化共享客户端
3. `cobra` 根据子命令路径路由到 `cmd/cmd-cast.go`
4. `cast` 父命令合并自身 flags 与继承自根命令的 flags，注入到 `cmd.Context()`
5. 具体业务子命令（`episode` / `movie` / `player`）从上下文中取出客户端，执行业务处理
6. 处理结果以退出码形式回传给 `main.go`，进程退出

由于社区曾就 Chromecast 兼容性提出 issue #5（"fix: properly do chromecast"），上述时序中真正负责"投放"动作的下层客户端逻辑是当前最受关注的稳定性点——若该层对设备发现或媒体会话处理存在边界条件，会直接表现为 CLI 调用失败。

资料来源：[main.go:5-15]()，[cmd/cmd.go:40-70]()，[cmd/cmd-cast.go:30-55]()

## 设计要点小结

- **薄入口**：所有逻辑下沉到 `cmd/` 目录，`main.go` 仅做引导
- **命令即模块**：每个子命令对应一个文件，便于独立阅读与测试
- **上下文传递**：通过 `cobra` 的 `cmd.Context()` 在命令树间共享依赖，而非使用全局变量
- **类型隔离**：剧集、电影、播放器三种业务互不干扰，扩展新类型成本低
- **社区关注点**：Chromecast 真实设备的兼容验证仍是开放问题，欢迎贡献者协助复现 issue #5

整体来看，`castor` 的架构体现了"以命令树组织业务、以上下文传递依赖"的典型 Go CLI 范式，数据流自顶向下单向流动，便于追踪与扩展。

---

<a id='page-3'></a>

## 隐匿浏览器提取与 AI 字幕生成

### 相关页面

相关主题：[系统架构与数据流](#page-2)

<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [internal/source/extract/extractor.go](https://github.com/stupside/castor/blob/main/internal/source/extract/extractor.go)
- [internal/source/extract/stealth.go](https://github.com/stupside/castor/blob/main/internal/source/extract/stealth.go)
- [internal/source/extract/profile.go](https://github.com/stupside/castor/blob/main/internal/source/extract/profile.go)
- [internal/source/extract/session.go](https://github.com/stupside/castor/blob/main/internal/source/extract/session.go)
- [internal/source/extract/snapshot.go](https://github.com/stupside/castor/blob/main/internal/source/extract/snapshot.go)
- [internal/source/extract/navigate.go](https://github.com/stupside/castor/blob/main/internal/source/extract/navigate.go)
</details>

# 隐匿浏览器提取与 AI 字幕生成

## 模块定位与职责

`internal/source/extract` 子包负责在不暴露自动化特征的前提下，从目标视频/直播站点抓取媒体流与字幕轨道。该模块对外屏蔽底层浏览器驱动差异，对内通过可插拔的策略将"加载页面 → 模拟用户 → 抓取快照 → 解析字幕"的流程统一为 `Extractor` 接口，支撑上游 `Source` 抽象的资源发现与转码流程。

- 顶层编排：[internal/source/extract/extractor.go](https://github.com/stupside/castor/blob/main/internal/source/extract/extractor.go) 定义了提取器的生命周期、错误重试策略，以及与字幕 AI 子系统的桥接点。
- 反检测核心：[internal/source/extract/stealth.go](https://github.com/stupside/castor/blob/main/internal/source/extract/stealth.go) 集中实现指纹伪装、请求头注入与 JS 环境覆盖。
- 用户态模拟：[internal/source/extract/profile.go](https://github.com/stupside/castor/blob/main/internal/source/extract/profile.go) 管理持久化的浏览器档案。
- 会话复用：[internal/source/extract/session.go](https://github.com/stupside/castor/blob/main/internal/source/extract/session.go) 维护 Cookie、LocalStorage 与访问令牌。
- 快照读取：[internal/source/extract/snapshot.go](https://github.com/stupside/castor/blob/main/internal/source/extract/snapshot.go) 解析渲染后的 DOM 与网络日志，提取媒体 URL 与字幕轨道。
- 导航控制：[internal/source/extract/navigate.go](https://github.com/stupside/castor/blob/main/internal/source/extract/navigate.go) 封装页面跳转、等待条件与回退逻辑。

资料来源：[internal/source/extract/extractor.go:1-80]()、[internal/source/extract/stealth.go:1-60]()。

## 隐匿机制设计

`stealth.go` 是模块的反检测中枢，通过多层手段降低被识别为自动流量的概率：

1. **指纹混淆**：覆盖 `navigator.webdriver`、`navigator.languages`、`navigator.plugins` 等关键字段，使其与真实 Chromium 一致 资料来源：[internal/source/extract/stealth.go:30-95]()。
2. **请求特征归一化**：统一 `User-Agent`、`sec-ch-ua`、`Accept-Language` 等头部，避免单实例特征固化 资料来源：[internal/source/extract/stealth.go:96-140]()。
3. **运行时注入**：通过 `Page.addScriptToEvaluateOnNewDocument` 提前植入脚本，确保页面在任何业务 JS 之前完成环境改写 资料来源：[internal/source/extract/stealth.go:141-180]()。

`profile.go` 与 `session.go` 共同提供"长期可信身份"：前者按主机维度持久化浏览器档案（字体、缓存、历史），后者负责 Cookie 续期与令牌刷新，使多次提取看起来像同一名真实用户的访问 资料来源：[internal/source/extract/profile.go:40-110]()、[internal/source/extract/session.go:25-90]()。

## 导航与快照捕获

`navigate.go` 将"进入页面"抽象为带超时的状态机：构造 URL → 应用前置脚本 → 等待 DOM 稳定 → 触发媒体播放器初始化事件。该文件同时实现回退策略（如遇到 Cloudflare 质询时切换到等待 challenge 自动通过的等待模式） 资料来源：[internal/source/extract/navigate.go:20-120]()。

完成导航后，`snapshot.go` 在渲染树稳定后调用 `Page.captureSnapshot` 等接口，采集 DOM 片段、网络响应缓冲以及 `window` 上的播放器实例引用。字幕轨道元数据（语言、kind、role）从 `<track>` 元素或播放器 SDK 暴露的清单中读取 资料来源：[internal/source/extract/snapshot.go:30-130]()。

## AI 字幕生成流水线

提取到的字幕分为两条路径处理：

- **原生字幕**：直接复用站点提供的 `.vtt`/`.srt` 轨道，仅做时基重映射与编码归一化。
- **AI 生成字幕**：当快照中未发现可用轨道时，`extractor.go` 将抽取的音轨片段交由外部字幕服务（Whisper/兼容 OpenAI 协议的本地推理）。流程为：切片 → 上传 → 流式接收分段结果 → 合并为 WebVTT → 写入共享缓存 资料来源：[internal/source/extract/extractor.go:120-210]()。

AI 结果会标注 `source: "ai"` 字段以便下游播放端展示来源；同一媒体的二次请求将命中缓存，避免重复推理成本 资料来源：[internal/source/extract/extractor.go:211-260]()。

## 数据流概览

```mermaid
flowchart LR
    A[Extractor 入口] --> B[Session 续期]
    B --> C[Stealth 注入]
    C --> D[Navigate 导航]
    D --> E[Snapshot 快照]
    E --> F{是否含原生字幕}
    F -- 是 --> G[归一化输出]
    F -- 否 --> H[AI 字幕生成]
    H --> G
    G --> I[Source 上层消费]
```

## 社区关注点

隐匿提取与 Chromecast 输出链路在社区 Issue #5 中被同时提及（"fix: properly do chromecast"），表明当提取结果下发到投屏设备时，AI 生成字幕的时基与编码需要与 Cast 协议兼容，否则会出现音画不同步。建议关注该 Issue 的后续进展以了解该模块的兼容性约束 资料来源：[internal/source/extract/snapshot.go:1-30]()。

## 扩展指引

新增站点接入时，只需实现 `Extractor` 接口并在 `stealth.go` 中追加必要的请求头模板，再通过 `profile.go` 注册独立档案即可隔离风控特征。`navigate.go` 的等待条件应优先使用业务事件而非固定延时，以减少被节奏检测识别的概率。

---

<a id='page-4'></a>

## 设备发现、DLNA 投射与 Chromecast 实验状态

### 相关页面

相关主题：[系统架构与数据流](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [internal/device/device.go](https://github.com/stupside/castor/blob/main/internal/device/device.go)
- [internal/device/dlna.go](https://github.com/stupside/castor/blob/main/internal/device/dlna.go)
- [internal/device/chromecast.go](https://github.com/stupside/castor/blob/main/internal/device/chromecast.go)
- [internal/device/didl.go](https://github.com/stupside/castor/blob/main/internal/device/didl.go)
- [internal/cast/replay/server.go](https://github.com/stupside/castor/blob/main/internal/cast/replay/server.go)
- [internal/cast/replay/pace.go](https://github.com/stupside/castor/blob/main/internal/cast/replay/pace.go)
</details>

# 设备发现、DLNA 投射与 Chromecast 实验状态

Castor 是一个面向本地网络的媒体投射工具，其核心能力由 `internal/device` 与 `internal/cast/replay` 两个子系统协作完成。前者负责在局域网中探测可用的渲染设备并将其抽象为统一的接口，后者负责按需建立可被播放器消费的 HTTP 数据源，从而使任意兼容 DLNA 或 Chromecast 协议的电视、音响能够流式拉取本地内容。

## 模块划分与职责

设备层被刻意拆分为协议无关的接口与各协议的适配实现，以隔离发现逻辑与具体通信协议。`internal/device/device.go` 通常承载通用结构（设备抽象、生命周期管理与广播事件），`dlna.go` 与 `chromecast.go` 则是面向具体协议的发现客户端。`internal/device/didl.go` 处理 DIDL-Lite 元数据，DIDL 是 DLNA/UPnP 用来描述媒体项的 XML schema，渲染端在收到 `SetAVTransportURI` 请求前必须以它作为入参。

资料来源：[internal/device/device.go:1-]()，[internal/device/didl.go:1-]()

## 设备发现工作流

```mermaid
flowchart LR
    A[Castor 启动] --> B[UDP SSDP M-SEARCH]
    B --> C{响应类型}
    C -- MediaRenderer --> D[DLNA 适配器]
    C -- Google Cast --> E[Chromecast 适配器]
    D --> F[统一 Device 接口]
    E --> F
    F --> G[上层 Cast 命令]
```

DLNA 的发现遵循 UPnP 规范：在 `239.255.255.250:1900` 上多播 `M-SEARCH` 报文，等待 `ST: urn:schemas-upnp-org:device:MediaRenderer:1` 的响应，再通过 HTTP `GET /device.xml` 与 `GET /service.xml` 拉取设备描述与服务描述，从而得到 `AVTransport`、`RenderingControl` 两个关键服务的 `controlURL` 与事件订阅端点。该流程主要由 `internal/device/dlna.go` 实现，并以结构体方式持有 `controlURL` 以便后续调用 `SetAVTransportURI`、`Play`、`Pause`、`Stop` 等动作。

资料来源：[internal/device/dlna.go:1-]()

## DLNA 投射链路

完成发现后，Castor 并不直接把本地文件路径交给渲染端，而是先在 `internal/cast/replay` 子系统中起一个本地 HTTP 回放服务器：

- `server.go` 提供 `GET /media/*` 这类按需字节范围（Range）请求端点，使得渲染端可以从任意时间点开始播放。
- `pace.go`（命名暗示 pacing，即“节拍控制”）负责按目标码率与 HTTP 响应节奏对数据进行限速或调度，避免一次性灌入缓冲或触发接收端缓存抖动。

当客户端选择一台 DLNA 设备并提交媒体 URL 时，Castor 通过 AVTransport 服务的 `SetAVTransportURI` 将上述本地 HTTP 地址注入渲染端，并把 DIDL-Lite 元数据（标题、时长、码率、分类等）附在请求体里。`didl.go` 负责把这些内部结构序列化为渲染端可解析的 XML 文档。

资料来源：[internal/device/didl.go:1-]()，[internal/cast/replay/server.go:1-]()，[internal/cast/replay/pace.go:1-]()

## Chromecast 协议的实验性状态

Chromecast 走的是与 DLNA 完全不同的栈：设备发现通常基于 mDNS（多播 DNS），控制协议则使用 Google Cast 的 Protobuf/JSON-over-WebSocket 通道。`internal/device/chromecast.go` 即为此适配层。

社区中尚未关闭的 [#5 "fix: properly do chromecast"](https://github.com/stupside/castor/issues/5) 明确指出，作者没有 Chromecast 实体可供联调，呼吁拥有设备的用户协助验证。这也意味着：

- 在 v1.4.0 中，Chromecast 路径在能发现设备的前提下仍可能存在握手、媒体会话（`LOAD`/`PLAY` 请求失败）或时间轴同步等未覆盖的边界。
- 与 DLNA 路径相比，Chromecast 适配未经过相同规模的回归测试，属于“可用但不保证”的实验状态。
- 提交 issue 时建议附上设备型号、固件版本与 `castor` 日志，以便对照 `chromecast.go` 中的连接/会话状态机排查。

资料来源：[internal/device/chromecast.go:1-]()

## 小结

| 协议    | 发现机制      | 控制通道                       | 当前状态     | 主要源码                           |
|---------|---------------|--------------------------------|--------------|------------------------------------|
| DLNA    | SSDP M-SEARCH | UPnP SOAP over HTTP            | 较成熟       | `device/dlna.go`、`device/didl.go` |
| Chromecast | mDNS        | Cast Protocol over WebSocket   | 实验性 (#5)  | `device/chromecast.go`             |

无论选择哪条协议，媒体数据的实际下发都依赖 `internal/cast/replay`，其中 `server.go` 提供按需字节流，`pace.go` 提供节奏控制，二者共同保证渲染端在长时间拉流过程中的稳定性。

资料来源：[internal/cast/replay/server.go:1-]()，[internal/cast/replay/pace.go:1-]()

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：stupside/castor

摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：安装坑 - 依赖 Docker 环境。

## 1. 安装坑 · 依赖 Docker 环境

- 严重度：medium
- 证据强度：runtime_trace
- 发现：安装/运行入口包含 Docker 命令：docker run --rm --network host ghcr.io/stupside/castor:latest scan # Cast, mounting config.yaml and a persistent model cache docker run
- 对用户的影响：非工程用户可能没有 Docker，启动成本明显增加。
- 复现命令：`docker run --rm --network host ghcr.io/stupside/castor:latest scan # Cast, mounting config.yaml and a persistent model cache docker run`
- 证据：identity.distribution | https://news.ycombinator.com/item?id=48964015 | docker run --rm --network host ghcr.io/stupside/castor:latest scan # Cast, mounting config.yaml and a persistent model cache docker run

## 2. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://news.ycombinator.com/item?id=48964015 | README/documentation is current enough for a first validation pass.

## 3. 运行坑 · 来源证据：fix: seems to lag after minutes of playing

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个运行相关的待验证问题：fix: seems to lag after minutes of playing
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/stupside/castor/issues/6 | 来源类型 github_issue 暴露的待验证使用条件。

## 4. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://news.ycombinator.com/item?id=48964015 | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://news.ycombinator.com/item?id=48964015 | no_demo; severity=medium

## 6. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://news.ycombinator.com/item?id=48964015 | no_demo; severity=medium

## 7. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://news.ycombinator.com/item?id=48964015 | issue_or_pr_quality=unknown

## 8. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://news.ycombinator.com/item?id=48964015 | release_recency=unknown

<!-- canonical_name: stupside/castor; human_manual_source: deepwiki_human_wiki -->
