CLAUDE.md · diff

git:20260809.6583e1a to git:20260809.d7bb7e4

84 added, 74 removed. Audit B to A.

# Project Agent Guide / 项目 Agent 指南
This file is the project-specific source of truth for AI agents working in this repository.
这是本仓库的项目级 AI 协作规则源文件。
+ ## 项目定位
+
+ `xxsj-fs-ob` 是一套运行在用户自己电脑上的信息收集系统,同时提供 Codex Skill 集成。
+
+ 当前正式实现:抖音视频采集 → 飞书多维表格任务队列 → 本地 Worker → Qwen-ASR → Faster-Whisper Large-v3 fallback → DeepSeek 摘要/分类 → Markdown → Obsidian → Base 回写。
+
## Scope / 范围
- Project root: this repository root.
- - Runtime: TypeScript Node.js CLI, Playwright, Vitest, pnpm.
- - Main command: `pnpm monitor`.
+ - Runtime: TypeScript Node.js CLI, Vitest, pnpm.
- Checks: `pnpm test` and `pnpm typecheck`.
+ - 主命令:Worker 通过 `scripts/start-worker.ps1` 或 `start-xxsj-fs-ob-worker.cmd` 启动。
- - 项目根目录:本仓库根目录。
- - 运行时:TypeScript Node.js CLI、Playwright、Vitest、pnpm。
- - 主命令:`pnpm monitor`。
- - 检查命令:`pnpm test` 和 `pnpm typecheck`。
+ ## 当前正式支持 (v1.0.0)
- ## Safety / 安全
+ - 抖音视频链接采集和处理
+ - 飞书多维表格任务队列
+ - Qwen-ASR 主转写
+ - Faster-Whisper Large-v3 备用转写
+ - DeepSeek 摘要、分类和值得保存的信息
+ - Obsidian Markdown 原子写入
+ - 去重、幂等、断点恢复、锁和冲突保护
+ - bot identity 无人值守 Base 读写
- - Never print or commit `.env`, Feishu tokens, LLM API keys, browser cookies, or Playwright profile contents.
- - `.env`, `.browser/`, `data/`, and `logs/` are local runtime state and must stay out of git.
- - Keep `.env.example` with blank secrets only.
- - Do not log full private message text unless the user explicitly asks for a local debugging readout.
+ ## 尚未正式实现
- - 不要打印或提交 `.env`、飞书 token、LLM API Key、浏览器 Cookie、Playwright 用户目录内容。
- - `.env`、`.browser/`、`data/`、`logs/` 是本地运行状态,必须留在 git 外。
- - `.env.example` 只能保留空白密钥占位。
- - 除非用户明确要求本地调试输出,不要在日志里输出完整私信正文。
+ - 公众号
+ - B站
+ - YouTube
+ - 推特 / X
+ - 小红书
- ## Douyin Monitor Rules / 抖音监控规则
+ 目录中存在不等于功能已实现。遇到未支持平台,Worker 会明确拒绝。
- - Prefer `HEADLESS=false` with `DOUYIN_OFFSCREEN=true`. Pure `HEADLESS=true` can trigger Douyin verification pages.
- - First login can use `DOUYIN_OFFSCREEN=false pnpm monitor`; normal use should run `pnpm monitor`.
- - Use `BROWSER_USER_DATA_DIR=.browser/douyin` to preserve login state.
- - `DOUYIN_OPEN_CHAT_TEXT` should be the visible self-chat name when auto-opening the target conversation.
- - The monitor intentionally ignores visible existing messages on startup when `DOUYIN_IGNORE_EXISTING_ON_START=true`.
- - Browser-mediated media capture lives in `src/media/douyinMediaCapture.ts`. It may save local media files, but must not print or persist signed media URLs, request headers, cookies, or session values.
- - Canonical public video links use `https://www.douyin.com/jingxuan?modal_id=<aweme_id>`. Media capture must use the exact matching detail response and fail instead of falling back to unverified page media.
- - Captured media must contain an audio stream before transcription.
- - Use local OpenAI Whisper through `scripts/transcribe-whisper.py` for transcription.
- - Default Whisper model is `base`; use `tiny` only for very quick smoke tests.
- - `TRANSCRIBE_COMPUTE_TYPE` is kept for queue compatibility but ignored by the OpenAI Whisper backend.
- - Convert Whisper transcripts and generated summaries from Traditional to Simplified Chinese before Feishu writeback.
- - Video deep processing is internal async queue work. `pnpm monitor` enqueues video records after Feishu write succeeds, then `VideoDeepProcessor` updates the same record by `去重 ID`.
- - Agnes AI can be used through the OpenAI-compatible summary path with `SUMMARY_MODE=openai` plus `AGNES_BASE_URL`, `AGNES_API_KEY`, and `AGNES_MODEL`. Never commit these values.
+ ## 平台 adapter 扩展原则
- - 优先使用 `HEADLESS=false` 加 `DOUYIN_OFFSCREEN=true`。纯 `HEADLESS=true` 可能触发抖音验证页。
- - 首次登录可用 `DOUYIN_OFFSCREEN=false pnpm monitor`;日常使用运行 `pnpm monitor`。
- - 使用 `BROWSER_USER_DATA_DIR=.browser/douyin` 保留登录态。
- - `DOUYIN_OPEN_CHAT_TEXT` 应填写自己会话在列表里的可见名称,用于自动打开目标会话。
- - `DOUYIN_IGNORE_EXISTING_ON_START=true` 时,启动时可见的旧消息会被忽略。
- - 浏览器媒体捕获逻辑在 `src/media/douyinMediaCapture.ts`。可以保存本地媒体文件,但不要打印或持久化签名媒体直链、请求头、Cookie 或会话值。
- - 公开作品链接统一使用 `https://www.douyin.com/jingxuan?modal_id=<aweme_id>`。媒体捕获必须使用精确匹配的详情响应;无法核验时直接失败,不使用页面媒体兜底。
- - 转写前必须确认下载媒体包含音轨。
- - 本地转写使用 `scripts/transcribe-whisper.py` 调用 OpenAI Whisper。
- - Whisper 默认模型是 `base`;只有快速冒烟时才临时用 `tiny`。
- - `TRANSCRIBE_COMPUTE_TYPE` 为队列兼容保留,OpenAI Whisper 后端会忽略它。
- - 飞书回写前,把 Whisper 转写和生成摘要中的繁体中文转换为简体中文。
- - 视频深度处理是内部异步队列。`pnpm monitor` 在飞书写入成功后入队视频记录,再由 `VideoDeepProcessor` 按 `去重 ID` 更新同一条记录。
- - Agnes AI 通过 OpenAI-compatible 摘要路径接入:`SUMMARY_MODE=openai` 加 `AGNES_BASE_URL`、`AGNES_API_KEY`、`AGNES_MODEL`。不要提交这些值。
+ 当需要添加新平台时:
+ 1. 创建新平台目录(如 `src/platform/bilibili/`)
+ 2. 实现平台 adapter 接口
+ 3. 在 Worker 中注册新平台
+ 4. 仅通过配置启用,不影响已有平台处理链
- ## Feishu Field Contract / 飞书字段契约
+ ## 目录结构
- The current MVP writes these fields only:
+ ```
+ xxsj-fs-ob/
+ ├── src/ # TypeScript 源代码
+ │ ├── analysis/ # 内容分析(DeepSeek)
+ │ ├── asr/ # ASR 转写编排(Qwen + Whisper fallback)
+ │ ├── base/ # 飞书多维表格适配器
+ │ ├── media/ # 抖音媒体捕获
+ │ ├── obsidian/ # Obsidian 写入
+ │ ├── pipeline/ # 处理管道
+ │ ├── summary/ # DeepSeek 摘要与分类
+ │ ├── video/ # 视频深度处理
+ │ ├── worker/ # 自动 Worker
+ │ └── config.ts # 配置管理
+ ├── scripts/ # PowerShell 和 Python 脚本
+ ├── tests/ # Vitest 测试 (25 文件, 229 tests)
+ ├── docs/ # 文档
+ ├── config/ # 配置模板
+ ├── references/ # 架构参考
+ └── SKILL.md # Codex Skill 定义
+ ```
- 当前 MVP 只写入这些字段:
+ ## Safety / 安全
- ```text
- 标题
- 内容类型
- 原始链接
- 原始文本
- 作者/来源
- 摘要
- 捕获时间
- 处理状态
- 去重 ID
- 错误信息
- 知识库链接
+ - 不要打印或提交 `.env`、飞书 token、LLM API Key、浏览器 Cookie、Playwright 用户目录内容。
+ - `.env`、`.browser/`、`data/`、`logs/` 是本地运行状态,必须留在 git 外。
+ - `.env.example` 只能保留空白密钥占位。
+ - 除非用户明确要求本地调试输出,不要在日志里输出完整私信正文。
+
+ ## 测试命令
+
+ ```bash
+ pnpm test # 25 测试文件, 229 tests
+ pnpm test:watch # watch 模式
+ pnpm typecheck # TypeScript 类型检查
```
- - Do not reintroduce Feishu fields `关键点` or `标签` unless the user asks for them again.
- - For video share cards, `标题` should come from the expanded Douyin caption. Exclude author metadata, publish time, collection text, and overlay controls such as `识别画面` and `个人观点,仅供参考`.
- - Video records write an empty `摘要` at first. After async deep processing succeeds, update `原始文本` with transcript text, `摘要` with transcript-based summary, and `处理状态=transcribed`.
- - `原始文本` should remain raw chat-card content, but standalone share-card author text must not be stored there.
- - `作者/来源` should contain the parsed author/source, including standalone Douyin share-card author text.
+ ## 安全规则
- - 除非用户重新要求,不要恢复 `关键点` 或 `标签` 两个飞书字段。
- - 视频分享卡片增强成功时,`标题` 应来自展开后的作品文案,并排除作者信息、发布时间、合集、`识别画面`、`个人观点,仅供参考` 等界面内容。
- - 视频记录初次写入时 `摘要` 为空。异步深度处理成功后,`原始文本` 更新为转写全文,`摘要` 更新为基于转写的总结,`处理状态=transcribed`。
- - `原始文本` 保持聊天卡片原始内容,但不要写入分享卡片里单独显示的作者名。
- - `作者/来源` 写入可解析到的作者或来源,包括抖音分享卡片里单独显示的作者名。
+ - 不读取真实 `.env`
+ - 不使用真实 Base 数据作 fixture
+ - 测试使用合成数据
+ - 不调用真实飞书、Qwen、DeepSeek、Whisper
+ - 不下载大型模型
+ - 不写入真实 Obsidian
- ## Documentation / 文档
+ ## 当前抖音正式支持范围
- - User-facing setup and operation live in `README.md`.
- - Manual validation lives in `docs/manual-smoke-test.md`.
+ - 飞书机器人接收抖音链接 → Base pending
+ - Worker 领任务:解析作品 ID → 下载视频 → Qwen-ASR 转写
+ - ASR 失败自动切 Faster-Whisper Large-v3
+ - DeepSeek 生成摘要、分类、值得保存的信息
+ - 生成 Markdown → 写入 Obsidian
+ - Base 状态回写 done
+ - 去重(Record ID + 平台作品 ID)
+ - 幂等(已下载不重复下载、已转写不重复转写)
+ - 断点恢复
+ - Obsidian 原子写入(冲突保护、用户修改检测)
- - 面向用户的安装和运行说明放在 `README.md`。
- - 手工验收步骤放在 `docs/manual-smoke-test.md`。
+ ## 公众号是下一优先级
+
+ 公众号内容采集与 Markdown 化是 v1.x 路线的下一个平台目标。