Commit c7f16ba1efd8dd488c70cb19a7ad95c107142cfc

Authored by yibo
1 parent daa45829

docs(lifelog): 转向纯端上 App,废弃 lemonPCRM + 端上 CRM 补齐 TODO

- 主线改为 lifelog-recorder(纯端上 Personal CRM),lemonPCRM(server/frontend/packages) 标已废弃,
  删掉 CLAUDE.md 里所有服务端章节(ACP/Master-Sub-Agent/GraphStore/server 微信链路)
- 加「App 即 Personal CRM:与旧 lemonPCRM 能力对比」+ 6 项差距 + 「Transcript→内部 Person」方向
- HANDOFF §五:存储 TTL/设置页标✅;「回链 lemonPCRM」→「内部 Transcript→Person」;
  新增「端上 CRM 补齐 TODO」P0–P3 清单

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CLAUDE.md
... ... @@ -4,164 +4,35 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4 4  
5 5 ## 项目概述
6 6  
7   -本仓库(`aipcrm/`)现在托管 **3 个互相关联但独立的子项目**:
  7 +本仓库(`aipcrm/`)的**主线 = `lifelog-recorder/`** —— Pixel 8 Pro 上一个**完全端上、零云端**的 Local-First 个人记忆 + 人脉管理(Personal CRM)原生应用:24/7 录音 + 本地中文 ASR + 声纹/人脸识别 + 端上 LLM 纪要/对话 + 以「人」为中心的联系人档案 + 全相册语义索引。所有能力跑在设备上,**不依赖任何 Mac/PC 服务**。
8 8  
9 9 | 子项目 | 路径 | 形态 | 状态 |
10 10 |---|---|---|---|
11   -| **lemonPCRM** | `server/` + `frontend/` + `packages/` | Node.js + Express 后端 + 静态前端 | 主线 |
12   -| **wechat_plain** | `wechat_plain/` | Android Xposed/A11y 模块 + Pixel 部署脚本 | 主线 |
13   -| **lifelog-recorder** | `lifelog-recorder/` | Pixel 原生 Android 应用(Kotlin + Compose) | v0.8 (2026-06) |
  11 +| **lifelog-recorder** | `lifelog-recorder/` | Pixel 原生 Android 应用(Kotlin + Compose) | **主线 v0.8** |
  12 +| **wechat_plain** | `wechat_plain/` | Pixel 上微信 bot 的 Xposed/A11y 模块(端上) | 辅助 |
  13 +| **lemonPCRM** | `server/` + `frontend/` + `packages/` | Node.js + Express 后端 + 静态前端 | **已废弃** |
14 14  
15   -**lemonPCRM** — lemonAI 出品的 Local-First AI 个人人脉管理系统(Personal CRM)。以人为中心、以对话为链接,通过知识图谱管理微信、LinkedIn、X 等多平台社交关系,将每个联系人与其社媒动态、会议纪要、文件、照片全面关联。
  15 +> [!IMPORTANT] 方向已转向纯端上 App
  16 +> 早期主线是 **lemonPCRM**(Mac 上 Node/Express + 知识图谱 + ACP 驱动 Claude CLI 的服务端 CRM)。
  17 +> 现已**废弃**:其 Personal CRM 能力已在 `lifelog-recorder` 里**原生端上重实现**(联系人档案、人脸/声纹识别、
  18 +> AI 印象、RAG 对话、照片语义检索),不再依赖 Mac。`server/` `frontend/` `packages/` 代码仅作历史留仓,
  19 +> **新功能不要往里加,也不要把 app 回链到它**。App 与旧 lemonPCRM 的能力对比 / 仍存差距见下文
  20 +> §lifelog-recorder「App 即 Personal CRM:与旧 lemonPCRM 的能力对比」。
16 21  
17   -AI 对话与编排层基于 ACP 协议驱动本地 Claude CLI 进程,提供单 Agent 执行和 Master → Sub-Agent 多轮编排能力。Node.js + Express,无数据库依赖(使用 Node 22.5+ 内置 `node:sqlite`),数据完全本地化。
  22 +### wechat_plain(端上微信 bot,辅助)
18 23  
19   -**wechat_plain** — Pixel 上微信 bot 的 Xposed/A11y 落地(A11y UI 自动化是当前唯一能真把消息推进 message 表的发送链路;详见下文 §微信集成架构)。
  24 +Pixel 上微信发送/跟踪的落地,纯设备内运行(不依赖 Mac):
20 25  
21   -**lifelog-recorder** — Pixel 8 Pro 上的 24/7 录音 + 本地中文 ASR + 时间轴 lifelog 应用(2026-06 新增,详见下文 §lifelog-recorder)。
22   -
23   -## 常用命令
24   -
25   -```bash
26   -npm run setup # 首次初始化:cp .env.example .env + pnpm install
27   -npm start # 生产模式(node server/index.js)
28   -npm run dev # 开发模式(node --watch server/index.js,热重载)
29   -./dev.sh # 杀掉端口占用进程 + npm run dev(推荐开发用)
30   -```
31   -
32   -无测试框架,无 lint 脚本。使用 pnpm workspaces(`packageManager: pnpm@10.28.1`)。
33   -
34   -## 架构
35   -
36   -### 技术栈
37   -- **后端**:Node.js (≥18) + Express,pnpm workspace monorepo
38   -- **数据库**:Node 22.5+ 内置 `node:sqlite`(`DatabaseSync`),位于 `server/db/lemon_crm.db`
39   -- **AI**:Claude CLI(本地子进程,`--dangerously-skip-permissions` 自动批准)
40   -- **文件解析**:mammoth(.docx)、pdf-parse(.pdf)
41   -
42   -### 目录速查
43   -
44   -| 目录 | 说明 |
45   -|------|------|
46   -| `packages/acp-core/` | ACP 协议层:Protocol / Transport / Launcher 三层抽象 + ClaudeCliProtocol / AcpProtocol |
47   -| `packages/agent-core/` | Agent 运行时(ESM):目录驱动的 Agent、AgentBus、AgentRegistry、AgentScaffold |
48   -| `server/index.js` | Express 入口(路由 + 静态前端) |
49   -| `server/src/core/` | 编排引擎:orchestrator、master-session、agent-manager、session-pool、stream-executor、prompt-builder、parser、runtime-resolver |
50   -| `server/src/engine/` | 进程层:run-registry、command-queue、process-guard、idle-timer、failover-error |
51   -| `server/src/tools/` | Master 工具:call-agent-tool、tool-registry、graph/(图谱 MCP 工具集) |
52   -| `server/src/standalone-entry.js` | 编程 API:`runMasterSession` / `runOrchestration` / `runSingleAgent` |
53   -| `server/routes/` | API 路由:master-chat、config、graph、wechat、import、analysis、photo |
54   -| `server/services/` | conversation-logger、file-parser、memory-service、claude-chat-service、wechat/、linkedin/、meeting/、photo/、x/ |
55   -| `server/db/GraphStore.js` | 本地知识图谱存储层(SQLite):Person / Organization / Project / Event / Asset 节点 + KNOWS / BELONGS_TO / PARTICIPATED 等边 |
56   -| `frontend/` | 静态前端(单 HTML 文件,由 server/index.js 托管) |
57   -| `server/config/backends.json` | ACP Launcher / Client 定义 |
58   -| `server/config/agents.json` | 静态 Agent 注册表(可选,也可由 `system/agents/` 目录发现) |
59   -
60   -### API 路由
61   -
62   -| 路径 | 说明 |
63   -|------|------|
64   -| `POST /api/master/chat` | Master Agent 多轮对话(SSE) |
65   -| `POST /api/master/upload` | 文件上传注入对话 |
66   -| `GET /api/master/sessions` | 列出活跃 session |
67   -| `DELETE /api/master/sessions/:id` | 关闭 session |
68   -| `GET/PUT /api/config/items/:key` | 读写配置文件 |
69   -| `GET /api/health` | 健康检查 |
70   -| `GET /api/graph/nodes` | 列出图谱节点(?type=Person&limit=100) |
71   -| `GET /api/graph/nodes/:id` | 查询单个节点(含边) |
72   -| `POST /api/graph/nodes` | 创建/更新节点 |
73   -| `GET /api/graph/search?q=关键词` | 全文搜索 |
74   -| `POST /api/graph/edges` | 创建关系边 |
75   -| `GET /api/graph/path?from=id&to=id` | 查询关系路径 |
76   -| `POST /api/wechat/import-contacts` | 导入微信联系人到图谱 |
77   -| `POST /api/wechat/import-chat` | 导入微信聊天记录 |
78   -| `GET /api/wechat/contacts?q=搜索` | 查询微信联系人 |
79   -| `GET /api/wechat/sessions` | 最近会话列表 |
80   -| `POST /api/import/...` | 多平台数据导入 |
81   -| `POST /api/analysis/...` | 图谱分析(关系链路、聚类等) |
82   -| `POST /api/photo/...` | 照片服务(人脸聚类、向量检索) |
83   -
84   -### 配置文件
85   -
86   -| 文件 | 说明 |
87   -|------|------|
88   -| `.env` | PORT(默认 3010)、HOST、CORS_ORIGINS 等 |
89   -| `server/config.js` | 端口、CORS、目录路径的运行时配置对象 |
90   -| `server/config/backends.json` | ACP Launcher 定义(command、args、protocol) |
91   -| `server/config/agents.json` | 静态 Agent 注册(可选) |
92   -
93   -## 关键架构模式
94   -
95   -### ACP 协议四层结构
96   -
97   -```
98   -Application (AgentManager)
99   - ↓
100   -Protocol (ClaudeCliProtocol 直接 spawn / AcpProtocol JSON-RPC)
101   - ↓
102   -Transport (ProcessTransport stdio / PipeTransport / WebSocketTransport)
103   - ↓
104   -Launcher (ProcessLauncher spawn / NoneLauncher 无操作)
105   -```
106   -
107   -`runtime-resolver.js` 根据 `backends.json` + `agents.json` 配置自动推断使用哪一层。
108   -
109   -**ClaudeCliProtocol 调用方式**:
110   -- 生成命令:`claude --input-format stream-json --output-format stream-json --verbose --include-partial-messages --dangerously-skip-permissions`
111   -- 输入格式:`{"type":"user","message":{"role":"user","content":[{"type":"text","text":"..."}]}}`
112   -- 输出:NDJSON 事件流
113   -- 单进程跨多轮复用(session reuse)
114   -
115   -**Mock 模式**:设置 `LEMONBOSS_CLAUDE_MODE=mock` 可读取 fixture 文件而不启动真实进程,用于调试。
116   -
117   -### Master → Sub-Agent 调度流程
118   -
119   -1. 用户消息 → `MasterSession.handleMessage()`
120   -2. `PromptBuilder` 组装系统提示(含工具描述 + 可用 Agent 列表)
121   -3. Claude 响应中的工具调用用 `[TOOL_CALL: tool_name] {...json...} [/TOOL_CALL]` 格式标记
122   -4. `ToolRegistry.parseToolCalls()` 解析后交给 `AgentManager.callAgent()`
123   -5. `SessionPool` 按 `agentName:client:deploy:workDir[:scope]` 为 key 复用已有 session
124   -6. 工具结果注回对话,最多循环 10 轮(`SAFETY_MAX_LOOPS=15`)
125   -
126   -**Orchestrator** 额外提供格式自动修正(`MAX_REPAIRS=5`)与结果验证(`ResultTracker`)。
127   -
128   -### Agent 发现与记忆
129   -
130   -- Agent 优先从 `system/agents/` 目录发现(目录驱动),`agents.json` 作为静态补充
131   -- 每个 Agent 的记忆存储在其目录下的 `memory/` 子目录,纯文件系统
132   -- `AgentScaffold` 用于创建新 Agent 目录结构
133   -
134   -### 知识图谱(GraphStore)
135   -
136   -`server/db/GraphStore.js` 使用 `node:sqlite`(Node 22.5+ `DatabaseSync`),无需额外依赖。
137   -
138   -- **节点类型**:Person、Organization、Project、Event、Asset
139   -- **边类型**:KNOWS、BELONGS_TO、PARTICIPATED、CONTAINS、MENTIONED_IN、ASSOCIATED
140   -- **分析状态**:`analysis_status` 字段跟踪节点是否已被 AI 分析(none / pending / done)
141   -- **Master 工具**:`server/src/tools/graph/` 提供 `create_person`、`get_person`、`link_persons`、`search_graph`、`get_relationship_path` 等工具供 AI 调用
142   -
143   -### 微信集成架构
144   -
145   -`server/services/wechat/` 提供从 Mac 和 Pixel 双端点与微信交互的能力:
146   -
147   -- **发送消息(实际工作链路)**:`am broadcast com.hermes.wechat.SEND_MSG` → **`HermesAccessibilityService`**(lsposed-wechat-sendmsg 模块内)→ 启动微信 LauncherUI → 点搜索按钮 → 搜索 `toUserDisplayName`(**必须传 nickname**,如"火星人")→ 点搜索结果 → 找 `bkk` 容器内的 EditText 输入文本 → 点 `bql` 发送按钮。纯 UI 自动化,绕开所有反射 / hook 失败。
148   -- **消息跟踪**:`android-wechat-tracker-sqlcipher.js` 直接轮询解密后的 `EnMicroMsg.db`(SQLCipher)
149   -- **自动回复**:`auto-reply.js` 结合 tracker + broadcast,在 Pixel 上独立运行
150   -- **数据导入**:`wechat-importer.js` / `wechat-reader.js` 将联系人和聊天记录导入知识图谱
151   -
152   -> [!WARNING] 关于其他两条已废弃的发送路径
153   -> - **LSPosed 反射 API**(`HermesWeChatModule.sendTextMessageDirect`):监听同一广播但走 `u01.r1.a → m1.a()`。`Send result: true` 是**误报**——`builder.a()` 后主线程异步提交触发 null 异常被 swallow,消息不进 `message` 表。
154   -> - **Frida daemon 队列**(`android-wechat-sender-frida.js` + `wechat_plain/scripts/frida-daemon/frida_daemon.js`):Frida 17 + 微信 8.0.72 注入大体积 bundle 触发反调试,微信进程崩溃,已废弃。
155   -> 这两条路径的命名让人误解;真正能把消息推进 message 表的只有 A11y service。
  26 +- **发送消息(唯一可用链路)**:`am broadcast com.hermes.wechat.SEND_MSG` → **`HermesAccessibilityService`**(lsposed-wechat-sendmsg 模块内)→ 启动微信 LauncherUI → 点搜索按钮 → 搜索 nickname(如"火星人")→ 点结果 → `bkk` 容器内 EditText 输入文本 → 点 `bql` 发送按钮。纯 A11y UI 自动化,绕开所有反射 / hook 失败。
  27 +- **已废弃的两条发送路径(命名误导,勿用)**:LSPosed 反射 API(`HermesWeChatModule.sendTextMessageDirect`,`Send result: true` 是误报,消息不进 `message` 表);Frida daemon(Frida 17 + 微信 8.0.72 注入大 bundle 触发反调试崩溃)。真正能推进 message 表的只有 A11y service。
156 28  
157 29 > [!IMPORTANT] A11y service 启用方式
158   -> `enabled_accessibility_services` 系统设置易被关闭。检查与重新启用:
  30 +> `enabled_accessibility_services` 系统设置易被关掉,重启:
159 31 > ```bash
160   -> adb shell "settings get secure enabled_accessibility_services"
161 32 > adb shell "su -c 'settings put secure enabled_accessibility_services com.hermes.wechat.xposed/com.hermes.wechat.xposed.accessibility.HermesAccessibilityService; settings put secure accessibility_enabled 1'"
162 33 > ```
163 34  
164   -详见 `server/services/wechat/README.md`。
  35 +详见 `wechat_plain/` 内文档。
165 36  
166 37 ## lifelog-recorder(Pixel 8 Pro 24/7 录音 + 本地中文 ASR + 本地 LLM,v0.8)
167 38  
... ... @@ -169,7 +40,7 @@ Launcher (ProcessLauncher spawn / NoneLauncher 无操作)
169 40  
170 41 ### 项目目标
171 42  
172   -把 Pixel 8 Pro 当成**永远开机的麦克风**:7×24 后台录音 → VAD 切段 → 中文 ASR 转文字 → 入库 → 按时间轴显示和搜索 → LLM 总结成纪要。最终目的是把所有「我说过 / 别人对我说过」的内容沉淀成可搜索、可回放的个人记忆库,下接 lemonPCRM 的人脉图谱(某段语音 → 某联系人 → 某项目)。
  43 +把 Pixel 8 Pro 当成**永远开机的麦克风**:7×24 后台录音 → VAD 切段 → 中文 ASR 转文字 → 入库 → 按时间轴显示和搜索 → LLM 总结成纪要。最终目的是把所有「我说过 / 别人对我说过」的内容沉淀成可搜索、可回放的个人记忆库,并在 **app 内自成端上 Personal CRM**(photolog):某段语音 → 声纹 → 联系人档案,照片 → 人脸 → 同一联系人。**整套 CRM 跑在设备上,已取代旧的 Mac 端 lemonPCRM**。
173 44  
174 45 约束:**完全本地 / 零云端依赖 / 月成本 0 元 / 隐私走 0 网络**。
175 46  
... ... @@ -273,19 +144,43 @@ Foreground Service (foregroundServiceType=microphone, WAKE_LOCK partial)
273 144  
274 145 剩余摘要:
275 146 - ⭐ **语义搜图落地**(v0.8 已接 `EmbedClient`,但需在 Pixel llama-swap 配 `embed` 模型才生效;中文 embedding GGUF)
276   -- ⭐ **回链 lemonPCRM**(Transcript / 照片 caption 实体 → GraphStore `MENTIONED_IN`,v2)
  147 +- ⭐ **内部 Transcript 实体 → Person 表**(端上 NER + 共现,取代旧「回链 lemonPCRM」;见下文 §下一步)
  148 +- ⭐ **微信抽取端上化**(消除 photolog 仅剩的 Mac 依赖;见下文差距分析 #6)
  149 +
  150 +### App 即 Personal CRM:与旧 lemonPCRM 的能力对比
  151 +
  152 +App(photolog)已覆盖、并在「联系人」维度超过旧 lemonPCRM 的核心:
  153 +
  154 +| 能力 | 旧 lemonPCRM(Mac/server) | 现 app(端上) |
  155 +|---|---|---|
  156 +| 联系人实体 | `Person` 图节点 | `Person`(融合 **声纹/人脸/微信/手机** 四模态,更丰富) |
  157 +| 多源导入 | 微信 / LinkedIn / X / 会议 / 照片 | 微信 + 手机通讯录 + 手动 + **24/7 录音(独有)** |
  158 +| 每人聚合视图 | 社媒动态 / 纪要 / 文件 / 照片 | 聊天 / 朋友圈 / 照片 / **录音** / AI 印象 / 简历(`PersonProfileScreen` 四 tab) |
  159 +| AI | Master Agent over 图谱(工具编排) | RAG 对话 over 转写/纪要(`LifelogRetriever`)+ AI 印象 |
  160 +| 照片 | 人脸聚类 + CLIP 检索 | 人脸聚类 + 语义检索(端上 ML Kit + ArcFace + Qwen-VL + embed) |
  161 +| 部署 | Mac Node 服务(依赖 Claude CLI) | **纯端上**(更隐私 / 零成本 / 零网络) |
  162 +
  163 +**仍存差距**(旧 lemonPCRM 有、app 还没有):
  164 +
  165 +1. **人↔人关系图**:app 只有 *人↔模态*(声纹/人脸/微信/手机)链接,**没有 person↔person 边**(KNOWS / 同事 / 同项目)。app 现在是「带富资料的扁平联系人表」,不是知识图谱。
  166 +2. **Organization / Project / Event 实体**:app 只有 `Person`/`Photo`/`Face`,没有组织/项目/事件节点。
  167 +3. **关系分析**:旧有 关系路径(`path`) / 社群发现(`communities`) / 待跟进(`followups`);app 三者皆无。
  168 +4. **AI agent / 工具编排**:app 是**纯 RAG 对话**,AI 不能对数据做动作(建人 / 连边);旧有 Master→Sub-Agent + 图谱工具(`create_person`/`link_persons` 等)。
  169 +5. **Transcript 内容 → 实体**:app 只按**声纹**把录音连到 `Person`(谁说的),**没有从转写文本抽人名/项目**做关联(旧 lemonPCRM 的 `MENTIONED_IN`)——这正是下一步要补的。
  170 +6. **微信抽取端上化**:微信联系人/头像/聊天/朋友圈仍由 **Mac 一次性抽取**(解密 `EnMicroMsg.db` + 抠头像)推到 `filesDir/wx_enroll/`,再由 `WeChatEnrollWorker` 端上入库。手机系统通讯录已完全端上;微信抽取是「纯 App」最后一块拼图。
  171 +
  172 +### 下一步:Transcript 实体 → 内部 Person 表(取代旧「回链 lemonPCRM」)
277 173  
278   -### 与 lemonPCRM 的关系
  174 +**不再回链外部 server**,改在 **app 内部**打通:从 `Transcript.text` / `Summary` 抽实体(人名/项目/地点,端上 LLM 或规则 NER)→ 与本地 `Person` 表匹配 → 建一张「提及」关系(新表 `mentions(segmentId, personId, ...)` 或 Person↔Segment 边)。让 `PersonProfileScreen` 除了现有「TA 自己说的」(声纹匹配段)之外,还能显示「**TA 被哪些录音提到、说了什么**」。这直接补差距 #5;同段被同时提到的人 → 共现边,又为差距 #1(人↔人关系图)打基础。
279 175  
280   -目前**完全独立**——lifelog-recorder 的 Room DB 跟 lemonPCRM 的 GraphStore 没打通。未来计划:把 Transcript / Summary 表里的实体(人名 / 地名 / 项目)抽到 GraphStore 当 `MENTIONED_IN` 边,让你的「某次会议说了什么」可以从图谱里反查。这是 v2 范畴。
  176 +> 上面 6 项差距的**可执行 TODO 清单(带优先级 P0–P3 + 做法)**见 `lifelog-recorder/HANDOFF.md` §「端上 CRM 补齐 — TODO」。路线:P0 #5 → P1 #1 → P2 #6。
281 177  
282 178 ## 注意事项
283 179  
284   -- `server/src/standalone-entry.js` 的 `loadConfig()` 优先读 `backends.json` + `agents.json`,无需数据库。
285   -- `prompt-builder.js` 的 `getSystemStateXML()` 只返回时间戳(公司/OKR 层已移除)。
286   -- Agent 目录内放 `SKILL.md` 文件会绕过协议封装,直接作为系统提示使用。
287   -- `server/index.js` 包含控制字符净化中间件:Agent 通过 curl 发送的 JSON body 可能含原始换行符,若解析失败会自动清理 `\x00-\x1F` 控制字符后重试。
  180 +- **构建**:`cd lifelog-recorder && JAVA_HOME=/opt/homebrew/opt/openjdk@17 ./gradlew :app:assembleDebug`,`adb install -r ...`。无测试框架。改 Room schema **必须写 Migration**(`AppDatabase` 已去 destructive 改 fail-loud;24/7 录音库静默清掉是大事故,见 memory `lifelog-room-migration-wipe.md`)。
  181 +- **改完即真机验证**:app 是 24/7 录音的命脉,改 `RecorderService` / 管线后务必装机看 logcat(`reconcile →` / `pipeline running` / `BlockProcessor`)确认录音没断。
  182 +- **`keys.properties` / `local.properties` gitignored**:讯飞凭证 + Hermes 端点 → `BuildConfig`;`sdk.dir` 换机要改。模板见 `keys.properties.example`。
  183 +- **`server/` `frontend/` `packages/`(旧 lemonPCRM)已废弃**:不再维护、不要往里加功能、不要让 app 依赖它。
288 184  
289   -> [!WARNING] (Agentic Self-Correction Loop Prevention)
290   -> **Master Agent 必读**:在 `Bash` tool 中使用含多重双引号的复杂命令(如 `curl -d '{"id":"lemonv"}'`)时,JSON 转义容易崩溃并陷入死循环。
291   -> **解决方案**:任何需要提交 JSON Payload 的操作,先写入 `/tmp/*.json` 文件,再通过 `curl -d @/tmp/payload.json` 发送。
  185 +> [!NOTE] 旧 lemonPCRM 的服务端架构(ACP 四层 / Master→Sub-Agent / GraphStore / 微信 server 链路)已从本文件移除。
  186 +> 如确需考古,查 git 历史里本文件的早期版本。
... ...
lifelog-recorder/HANDOFF.md
... ... @@ -254,11 +254,35 @@ Tier-0 PhotoFaceWorker (15min, battery-not-low) Tier-1 PhotoVlWorker (1
254 254  
255 255 剩下:
256 256  
257   -1. **存储 TTL**:删超过 N 天的 .opus,文字永留。Periodic WorkManager job。
258   -2. **设置页**:存储用量、模型切换、provider 切换、暂停时段配置(v1 定的 MVP 是「一键暂停就够」,但 v2 可能要细化)。
  257 +1. ✅ **存储 TTL**(2026-06-08 完成):`StorageManager.prune` 按天目录删超期 .opus、文字永留;每天 periodic worker;设置页「存储」段(用量 + 保留时长 + 立即清理),默认永久保留。
  258 +2. ✅ **设置页**(基本完成):`SettingsScreen` 已含 纪要模型后端 / 聚类·合并·最短识别阈值 / llama-swap 端点 / 分段间隔 / **定时不录(quiet hours)** / 存储用量+TTL / 电池豁免。
259 259 3. ✅ **多 anchor 平均**(2026-06-07 完成,L2):重命名/合并某说话人时 `rebuildAnchor` 用该人名下全部段的均值重建 anchor,取代单段注册。
260   -4. **回链 lemonPCRM**:Transcript 提到的人名 / 项目 → GraphStore `MENTIONED_IN` 边。
  260 +4. **内部 Transcript 实体 → Person 表**(取代旧「回链 lemonPCRM」):在 **app 内部**从 `Transcript.text`/`Summary` 抽实体(人名/项目,端上 LLM 或规则 NER)→ 匹配本地 `Person` → 建「提及」关系(新表 `mentions(segmentId, personId)`),让人物档案显示「TA 被哪些录音提到」(现仅显示「TA 自己说的」=声纹段)。同段共现的人 → 人↔人边。**不再回链 Mac 端 lemonPCRM**(已废弃)。
261 261 5. ✅ **hermes gateway 自启**(2026-06-04 完成):用 Magisk `service.d` 脚本开机拉起(Termux:Boot 未装,root 方案更稳),见下方「§ 自启(Magisk service.d)」。
  262 +6. **微信抽取端上化**:消除 photolog 仅剩的 Mac 依赖(微信联系人/头像/聊天/朋友圈现由 Mac 一次性抽取推到 `filesDir/wx_enroll/`)。
  263 +
  264 +### 端上 CRM 补齐 — TODO(对齐并超越旧 lemonPCRM)
  265 +
  266 +> 旧 Mac 端 lemonPCRM 已废弃,能力在 app 内重建。下表是「app 当前缺、旧 lemonPCRM 有」的 6 项,
  267 +> 按优先级排(P0 先做)。能力对比详见 CLAUDE.md §「App 即 Personal CRM」。
  268 +
  269 +- [ ] **P0 · #5 Transcript 内容 → Person「提及」关系**(最高价值,最贴 app 形态)
  270 + - 现状:录音只按**声纹**连到人(谁说的);不从转写文本抽人名/项目。
  271 + - 做法:块处理后(或事后 worker)对 `Transcript.text` 抽实体(端上 LLM 4B 或规则/词典 NER)→ 匹配本地 `Person`(name/realName/nickname/alias,拼音兜底)→ 写新表 `mentions(segmentId, personId, name, confidence)`(Room 迁移 +1)。
  272 + - 出口:`PersonProfileScreen` 加「被提到」tab(现只有「TA 自己说的」=声纹段)。
  273 + - 依赖:端上 4B 已就绪(llama-swap 8080)。
  274 +- [ ] **P1 · #1 人↔人关系(共现边)**
  275 + - 做法:基于 #5,同一会话/时间段被同时提到 + 同时在场(声纹)的人 → `relations(personA, personB, kind, weight)` 共现/认识边,weight 随共现次数累加。
  276 + - 出口:人物档案「相关的人」;后续可做关系图可视化。
  277 +- [ ] **P2 · #6 微信抽取端上化**(消除最后的 Mac 依赖,工程债)
  278 + - 现状:微信联系人/头像/聊天/朋友圈由 Mac 解密 `EnMicroMsg.db`(SQLCipher)+抠头像,推到 `filesDir/wx_enroll/`。
  279 + - 做法:把解密+抽取搬到端上(root + SQLCipher key 端上取),`WeChatEnrollWorker` 直接读微信库;配方见 memory `wechat-android-decrypt.md` / `wechat-avatar-face-enrollment.md`。
  280 +- [ ] **P3 · #2 Organization / Project / Event 实体**(产品决策:要不要从「联系人表」长成「图谱」)
  281 + - 新增节点类型 + 与 Person 的边(属于/参与);可由 #5 的实体抽取顺带产出(项目名/公司名/事件)。
  282 +- [ ] **P3 · #3 关系分析**:关系路径(两人间最短链)/ 社群发现(聚类)/ 待跟进(followups:从录音承诺「下周给他发X」抽待办)。依赖 #1 的关系边。
  283 +- [ ] **P3 · #4 AI 能对数据做动作(agent/工具编排)**:让对话 AI 不止 RAG 问答,还能调工具建人/连边/改资料(端上轻量 tool-calling,Hermes 或本地模型)。最大、最后做。
  284 +
  285 +> 路线:**P0(#5) → P1(#1) → P2(#6)**,三步把「录音→人→关系」在端上闭环;P3 三项是「要不要把 app 升级成真·知识图谱 + AI agent」的产品选择,按需再开。
262 286  
263 287 ### hermes gateway 设置(v0.5 关键前置)
264 288  
... ...