-
Notifications
You must be signed in to change notification settings - Fork 2
Changelog zh
⚠️ 修一个潜伏所有版本的 db corruption 根因:FTS5 全文索引 segment 失控膨胀导致~/.memora/memora.db涨到 6 GB,最终磁盘满 → SQLite "database disk image is malformed" → 所有 ingest 失败 → UI 数据冻结。所有用户都建议升级(你的 db 可能也在膨胀)。
crates/memora-core/src/db.rs::ingest_session 之前是"全量替换"模式——每次 raw 文件 size 变化(FSEvents 每次 jsonl append 都触发),就 DELETE FROM messages WHERE session_id = ? + INSERT all。FTS5 contentless 模式下 DELETE 写 tombstone segment、INSERT 写新 segment,auto-merge 跟不上 churn → segments 累积到 94 万(messages 才 4.5 万行,21 倍异常)→ fts_data 涨到 3.6 GB → db 涨到 6 GB → 磁盘满 → wal 写 ENOSPC → 半写 frame → database disk image is malformed。
修法:ingest_session 改增量——先 SELECT existing message id 集合,只 INSERT 不在集合里的(CC append-only + parse_session 已 dedup → 安全)。effect: sync 一个长了 3 条的 jsonl 只产生 3 个 FTS segment(之前是 500 个)。
自更新拿到 v0.5.7 之后,老 db 还是膨胀状态——可以手动跑一次 hot fix 缩 db:
pkill -f "Memora.app/Contents/MacOS/memora"
sqlite3 ~/.memora/memora.db "INSERT INTO messages_fts(messages_fts) VALUES('rebuild'); VACUUM;"
open /Applications/Memora.app本机实测 6.35 GB → 34 MB(缩 99.5%),耗时 ~2 秒,数据零丢失(108 sessions, 45216 messages 不变)。
- windowID ↔ session 映射:私有 AX API 拿 focused window CGWindowID,hook 触发时绑定,同 ghostty 多窗口能精准识别"焦点哪个标哪个 session"
- 摘要 cross-source 综合:LLM 注入 git branch + 关联 commits + prompt 硬约束保留版本号/hash/数字
- 同 app 多窗口切换 Beacon 重新计算:Swift fromAX 不 dedupe + Dart 去掉 project.id 去重
- iTerm2 BFS:4 层穿透 iTerm2 → iTermServer → login → zsh 找 shell
- 自更新 helper 自动清 quarantine:飞书/AirDrop 等渠道传播也能直接启动
- build.sh 在打 DMG 前先 staple .app:之前只 staple DMG,从 DMG 拖出来的 .app 没 ticket,离线/VPN 异常时无法首次启动
- 终端类窗口用 PID → cwd 反查项目:Codex CLI / 普通 cd 终端也能展开 Beacon
自动更新上线 + Beacon 焦点窗口优先 + 黑板带 session 回顾摘要 + 代码 0 warning。从此版本起,你不再需要手动下载 DMG。
-
自动更新(Auto-Update): 启动时静默查 GitHub Releases API,有新版本立刻后台下载 DMG 到 systemTemp。下载完主界面顶部出现紫色 banner "Memora vX.Y.Z 已下载 · 重启完成更新"。用户点 "立即重启" 后,主进程写一段 helper bash(hdiutil attach → cp .app → detach → relaunch)然后
exit(0),helper 静默完成替换并拉起新版本。Settings → About 区也有 "检查更新" 入口,可看进度/重试。不做自动重启——用户可能正在调试,强行重启会丢上下文。 -
Session 回顾摘要: 项目详情页每张 session 卡片下方新增一段 LLM 生成的会话摘要,跟着 UI 语言。Prompt 不写 commit message 风格的"做了什么",而是覆盖三个维度:
- 起因: 用户为什么发起这次对话
- 过程: 讨论了什么、走了哪些方向、试过什么
- 阶段性进展: 完成 / 决定 / 待办 / 还在讨论 / 卡住
目的:让用户日后翻 session 列表时能瞄一眼判断"这个会话跟我想找的东西相关吗"。
- 触发: 点"黑板"按钮时顺带触发,按钮上显示进度 "总结对话 12/33"
-
缓存:
~/.memora/session-summaries/<session_id>.json,messageCount不变就跳过 LLM - 并发: 3 路并行
- 无 LLM: 静默不显示该行
-
Beacon 后台 hook 抢走焦点窗口的项目展示: 用户在 Memora 窗口编辑代码时,speakout 后台的 claude session 触发 Hard Allow hook,Beacon 突然切到 speakout。修法:
notifyActiveProject简化成只记录_lastHookProjectPath(供 window title 为空时回退),不再写_lastMatchedProjectId、不再触发 expanded 推送。窗口聚焦成为 Beacon 项目上下文的唯一来源。 -
审批弹出后 dismiss 不恢复用户原始意图: 之前
dismissNotification写死"前台 app 是编程类 → expanded",违背"用户在审批弹出前手动收缩了 → 审批结束应该回到 collapsed"的常识。新加stateBeforeNotification快照,dismiss 时优先恢复快照值。
-
代码 0 warning:
flutter analyze之前 20 个 issue + Swift 编译 1 个 unused var,本版全部清完。flutter test: 297/297 全过。 - 新增
lib/src/update_service.dart(精简自 speakout,~230 行)。
Beacon 展开态多 session 聚合 + 项目级 agent 配置对比。
-
Beacon 展开态多 session 聚合 — 之前只描述单 session,忽略了 Memora 相对 CC recap 的独占价值(CC 看不见别的窗口)。现在 top 3 活跃 session 并列输出,每行一个 session,标
(当前)区分用户焦点,可选最后一行"待你决定:..."。 -
精准识别"用户当前在哪个 session" — hook 写
ppid(=claude进程 PID);Dart 端维护_sessionByPid映射;前台终端 PIDpgrep -P递归找 CC 后代;pgrep -x claude+lsof -p <pid> -a -d cwd给出"本项目活着的 claude 数"作为上限。失败 fallback 到 jsonl mtime。 -
Beacon 展开态动态高度 — 用
NSString.boundingRect实测文本高度,clamp 到 3-6 行(51-102pt)。140/180 字的长 summary 不再被硬 48pt × 3 行上限吞掉尾巴。 -
项目级 agent 配置对比 — 项目详情页出现 2+ agent 配置(
CLAUDE.md/AGENTS.md/AGENTS.override.md/.cursorrules/.claude/CLAUDE.md/.codex/AGENTS.md)时,L2 section 标题右侧出现"对比 & 同步"按钮,双列 LCS 行级 diff,列头文件名可点击用默认编辑器打开自行修改。
-
LLM 看不到真对话乱凑总结 —
file-history-snapshot之类的元数据记录单条 5KB,把 2000 字节 tail 窗口塞满,真对话被挤出。新 transcript 预过滤器只留 User/AI 文本;tail 从 2000 字节扩到 12000 字节 → 过滤后 1800 字/session。 -
异步 race 导致显示错项目 —
_sendExpandedData长 async,用户快速切窗口时旧请求可能覆盖新请求。_pushExpandedData前加_lastMatchedProjectIdguard。 -
hot session 把僵尸拉进来 — 三层滤:mtime < 2h +
_sessionByPid已知死的剔除 + 按本项目活 claude 数封顶。 -
LLM 输出字面
\n被当文本 — prompt 用真换行 + 兜底replaceAll(r'\\[nN]', '\n')。 - Summary 字数上限 — 80 → 140/180(对齐 tweet 心智模型)。
修 CC v2.1.114+ queued prompt 在 Memora 里不显示的问题。
-
CC v2.1.114+ 的 queued prompt 在 UI 里缺失 — CC 更新后,用户在工具跑完前输入的 prompt 会被 queue。transcript 里新出两种记录:
type:"queue-operation"(enqueue 瞬间 transient)和type:"attachment"+attachment.type:"queued_command"(CC 真正处理时写入,含prompt)。Memora ingest 只 matchuser/assistant,两种都被丢 → UI 里看不到用户这条 prompt,只见 AI "凭空回答"。修法:claude_code.rs加RawAttachmentstruct +queued_command独立分支;queue-operation保持丢弃(attachment 已覆盖,避免重复入库)。2 个新单元测试。 -
历史 session 自动回填 —
~/.memora/raw/claude-code/中含 queued_command 的 session 会在下次 sync 时自动重新 parse,补回之前丢失的用户气泡。无需用户操作。
修 git -C <path> 绕过 deny-list 的安全漏洞 + 对话历史图片可点击查看。
-
git -C /path ...绕过 deny-list(安全问题) — CC 常用git -C /abs/path <subcmd>在指定目录跑 git,但 deny-list 的 7 条 git 规则全都是^git\s+push\s+...形式,遇到git -C /victim push --force正则不匹配,直接放行进入 LLM 层 —— LLM 有概率判 allow,是真实 bypass。hard-allow 的_gitReadCmd/_gitWriteCmd同样漏判,导致git -C /path log ...白白等 7–8 秒。修法:helpers.dart新加kGitCmdPrefix正则片段(覆盖-C <dir>、-c <k=v>、--git-dir[=|空格]<path>、--work-tree[=|空格]<path>,可重复可缺省),hard-allow 两条正则 + deny_list 全部 7 条 git 规则一起加前缀。5 个 prefix-bypass 回归测试。
-
对话历史图片引用可点击查看 — 消息正文里的
[Image: source: /abs/path.png](CC 附件元数据)现在渲染成紫色可点击"📎 图片"链接,点击用系统open拉起默认看图 app。[Image #N]无路径占位符渲染成灰色标签。文件不在时 SnackBar 提示。最小实现:不复制、不持久化;parseMessageSegmentspure-Dart 拆段 +SelectableText.rich+TapGestureRecognizer;9 个边界测试。
省心模式体验打磨。
-
Hard Allow 漏判引号里的 pipe —
_isDefinitelySafe按|;&切命令不懂 shell 引号,grep "A\|B\|C" file被切成破碎段、降级走 LLM。新增 shell-aware 预处理:遇到$(...)/ 反引号直接 bail-out;否则先剥"..."/'...'再 split。常见带 regex alternation 的 grep 重回第 2 层瞬时放过,不弹通知、不等 LLM。 -
Auto-allow 后面板残影 1–2 秒 — 省心模式下 LLM 出
allow后,_autoAllowRequest写响应文件 + 删请求文件,但原生 Beacon 面板要等BeaconService下一次 scan 周期(~2s)才收。新 publicBeaconService.dismissById(reqId):同步清 active id + 推进队列 + 发 native dismiss。Lark 先响应路径同步调用。 - 展开态 Beacon 面板挡住背后内容 — 点面板空白区域之前不响应;现在点非按钮区域就收缩回小圆点,方便看被遮住的代码;窗口 title 变化时自动重新展开。"Open in Memora" 保留在按钮上。
Risk Engine + Channel 抽象 + 两种操作模式。Memora 从"被动通知层"演进为"有判断力的代理层"。
-
Channel 抽象 —
ChannelRegistry把每个请求 fan-out 到所有启用 channel(本地 Beacon / 飞书 Lark),first-response-wins,其他自动 dismiss。 -
Risk Engine 三层决策 — Hard Deny(
rm -rf、凭据路径、git push --force...) / Hard Allow(项目内编辑、只读命令、构建测试、日常 git) / 灰色地带 → LLM advisor(DeepSeek / Claude / OpenAI),静态 + raw 两层 fallback。 - 新 Approval UI — 语义动词、AI 建议、关键参数高亮,替代 raw shell 显示。
-
两种操作模式 — 正常(默认):deny/hard-allow 之外都弹通知,LLM verdict 作为参考。省心(手动开):LLM 判
level != high && rec != deny全部 auto-approve。 -
自动刷新 — FSEvents 监听
~/.memora/raw/+ 60s 兜底轮询。sessions 自动更新无需点刷新。
- 项目误匹配(case-insensitive + longest-prefix)。
- Accessibility 权限被 adhoc 签名撤销(CLAUDE.md 禁止
flutter build + cp,必须走./build.sh)。 - Hook 协议:
toolInput缺失时从requestDetail回退;路径正则修复空格。 - Deny-list 收紧:基于 13005 条真实命令评估,FP -86%(
docs/risk-evaluation-report.md)。
完整细节见 release v0.4.0 和仓库内 CHANGELOG.md。
-
Hook adhoc 签名 → Developer ID(
build.sh):v0.3.0 发出去的memora-hook是 cargo 默认的 ad-hoc 签名。macOS 14+ Gatekeeper 在执行时会直接 SIGKILL ad-hoc 签名的 CLI 二进制(exit 137),导致所有 PreToolUse / PostToolUse hook 在用户机器上静默失败——Memora 捕获不到任何 hook 事件。v0.3.1 在include_bytes!把 hook 字节冻结进 .app 之前用 Developer ID Application 重签。Hook 的 CDHash 经 Apple 公证传播到 .app 公证记录里,用户首次跑 hook 时 Gatekeeper 在线查 CDHash 命中通过。已经在跑 v0.3.0 的用户必须升级。
-
Settings 中的 Hook 版本检查:Settings → Hooks 显示已安装的
memora-hook版本和期望版本,不一致时显示琥珀色警告 banner + 重装说明。memora-hook新增--versionflag。 - Beacon 通知声音可配置:Settings → General 可选 14 种系统声音(或无声),每个选项有预览按钮。
- 设置界面重构:760×560 双栏布局,macOS 风格左侧边栏(General / LLM / Personas / Hooks / About),替代原来的单栏滚动。
-
Beacon 展开面板文字残留:
updateState多次调用累积了过期的NSTextField子视图。现在用dynamicContainer模式,每次 transition 时清空所有动态子视图。 - Beacon 点击意图:之前点击展开面板任何位置都会跳到主程序。现在只有明确的 "Open ↗" hit rect 会触发跳转。
-
显示器热插拔后下拉框过期:Swift 通过
beacon:displaysChanged主动通知 Dart,加上PopupMenuButton.onOpened打开时再 fetch 一次。 -
Beacon sentinel 存活检查:PreToolUse 不再依赖过期的 sentinel PID(加
kill(0)校验),避免匹配的 Beacon 进程崩溃后还在放行请求。 -
Hook 协议——空 stdout ≠ allow:hook 始终显式写
permissionDecisionJSON,不依赖 Claude Code 的隐式默认。
- 新增 Rust API
hook_version_status(),通过 flutter_rust_bridge 暴露为check_hook_version()。 -
build.sh --no-bumpflag 用于精确版本号的 release build。 -
NSScreen.didChangeScreenParametersNotification触发 Swift→Dart method channel callback,让 Flutter 不用轮询就能刷新显示器列表。
-
基于文件的授权通信:Hook 轮询
~/.memora/beacon-responses/<toolUseId>.json最多 30 秒,超时后回退到终端确认。完全替代脆弱的按键模拟——跨 macOS Space、跨多窗口终端、任何焦点状态都可靠。 -
AXDocument 项目检测:直接读
kAXDocumentAttribute(OSC 7 cwd),不依赖窗口标题。Ghostty / Terminal / iTerm2 / Warp 开箱可用。 - 首选显示器设置:可将 Beacon(项目信息 + 通知)固定到指定显示器。对多屏用户尤其关键(如竖屏副屏上 Beacon 看不到时通知会被错过)。
-
per-request resolved 追踪:PostToolUse 写
toolUseId(不是时间戳)→ 通知队列也能精确匹配 dismiss。 - 通知队列:多个 PreToolUse 请求依次显示,不会丢失。
- 快速切换项目时 UI 不更新(
transitionTo在 state 未变时早返回,导致旧数据残留)。 - 通知面板在外接屏(无 notch)上按钮被裁切(高度算式没用统一的 topArea)。
- Hook 超时后通知卡住——hook 超时时主动删除请求文件,让 Dart 自动 dismiss。
- 响应文件孤儿堆积——Dart 启动时清理
~/.memora/beacon-responses/中超过 30 秒的旧文件。 -
flutter build macos产生 ad-hoc 签名 → 必须用build.sh才能拿到正确的 Developer ID 签名(否则辅助功能权限会被撤销)。
- 删除所有按键模拟代码(
sendKeystrokeToTerminal、findAndRaiseTerminalWindow、raiseWindowContaining、sendKeyCodeToPid、keystrokeForAction)—— ~100 行脆弱的 AX/CGEvent 代码被文件通信完全替代。
- 菜单栏上方的浮动面板,像素螃蟹吉祥物
- 授权双通道:Beacon 和终端同时显示 Allow/Deny
- 按键转发
CGEvent.postToPid()— 不切换焦点 - 可配置的权限规则(按来源+工具)
- 凹弧形状 — 面板从屏幕边缘"生长"
- 上下文感知状态机(收缩/展开/通知)
- 点击展开态 → 在 Memora 中打开项目
- Continue V2:跨工具工作区创建——git clone + MEMORA_CONTEXT.md,包含完整对话历史、git log 和项目文件
- Drift Awareness:Blackboard 中的计划与实际工作对比面板,带用户裁决按钮
- Context-Linked Commits:Hook 检测 AI session 期间的 commit 并关联到对话
- 新手引导:6 步交互式引导,带聚光灯覆盖层
- 国际化:英文 + 中文语言支持
- 自动 Git 保护:每次同步时自动提交 ~/.memora/ 数据
- 设置:Hook 重装按钮
- Blackboard 视图切换:Insights | vs Plan
- 前进/后退 commit 导航按钮
- 搜索:关键词高亮、摘要片段、结果计数
- Session 时间线:右键 commit 可 Recall/Branch
- Branch 对话框:Clone 模式添加浏览按钮
- Drift 读取策略文件全文;Continue 上下文扩展到 50 commits + 10 sessions
- 响应式 Blackboard 卡片,fullSizeContentView 标题栏
- 通知自动消失竞态条件
- 启动时清理残留请求文件
- AXObserver 即时窗口切换检测
- commit-link 处理移到 git sync 之后(防止关联丢失)
- Drift 裁决取消正确持久化到 DB
- 分支过滤器显示空状态而非静默回退
- 从 Git 保护中排除 *.db(之前导致磁盘膨胀)
- flutter analyze 0 issues, flutter test 52/52 pass
- 双轨时间线(对话 + Git commit)
- Blackboard(AI 驱动的项目分析)
- History Branching(Worktree 和 Clone 模式)
- 消息级 Continue(导出为 Markdown)
- 六层知识模型(L1-L6)
- 多提供商 LLM 支持(12+ 提供商)
- 跨对话和 commit 的全文搜索
- 代码签名 + DMG 打包
- 首次发布
- Flutter + Rust 架构
- Hook 驱动的对话捕获
- Claude Code、Codex、OpenCode、Cursor 支持