@fanchao8609/agent_brain_sync 1.2.1 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,96 +1,123 @@
1
- # abs — agent-brain-sync 跨会话 AI 编码记忆
1
+ # abs — agent-brain-sync
2
2
 
3
- 跨会话记忆的机械落盘:**hook 纯触发 → CLI/MCP 读写 → markdown 图谱(`.brain/`,可进 git)**。
4
- 让每个会话不再无状态——经验/进度/踩坑有统一落点,重开不"失忆"。
5
- 参考 [ai-memory](https://github.com/akitaonrails/ai-memory) 的接入机制,砍掉全部重引擎。
3
+ **跨会话 AI 编码记忆。** 让 AI 会话不再「重开就失忆」:任务进度、经验、踩坑都落盘到项目里的 markdown 图谱,下一个会话开机能直接读回来。
6
4
 
7
- > npm 发布名 `@fanchao8609/agent_brain_sync`(因 `agent-brain-sync` 已存在、相似名被 npm 拦截);全局命令 `abs`(包名与命令名独立)。
5
+ - 图谱纯 markdown,放在项目根 `.brain/`,**可以进 git**,人和 AI 读同一份
6
+ - 多项目自动隔离:从当前目录向上找最近的 `.brain/`
7
+ - 并发安全:CLI / MCP / hook 同时写不会互相覆盖
8
8
 
9
- ## 架构
9
+ npm 包名 `@fanchao8609/agent_brain_sync`,全局命令 **`abs`**。
10
10
 
11
+ ---
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ npm install -g @fanchao8609/agent_brain_sync
17
+ abs install
11
18
  ```
12
- hook (宿主事件, 纯触发) ──▶ abs log (一行技术流水, fire-and-forget, 不阻塞)
13
- agent (会话中) ──▶ MCP (abs_load/abs_board/abs_task/…) ──▶ 读写 .brain/
14
- 人 (终端) ──▶ abs CLI 同一套读写
19
+
20
+ `abs install` 会交互式让你勾选智能体;也可以直接指定:
21
+
22
+ ```bash
23
+ abs install --agent pi # 只装 pi
24
+ abs install # 全部: claude-code / codex / opencode / pi
25
+ abs install --agent pi --no-mcp # 只装 hook + skill,不要 MCP
15
26
  ```
16
27
 
17
- - **唯一真源**: `<项目>/.brain/`(index/todo/log + concepts/entities/sources/syntheses/sessions)
18
- - **多项目隔离**: 任何读写先从 cwd 向上找最近 `.brain/`(代码写死,MCP 无状态,各会话各归各位)
19
- - **三层分工**:
20
- - **hook(机械层)**:宿主生命周期事件 → 只写技术日志(`~/.abs/log/`),不碰图谱 todo/log.md
21
- - **CLI/MCP(实时层)**:任务/经验实时落盘(`abs task start/note/blocked/done`、`abs note`)
22
- - **skill(自觉层)**:深提炼(sources→concepts)+ 收尾循环(详见 skill/SKILL.md)
23
- - **并发写保护**: 所有 .brain 读改写经 `lock.editFile`(`open wx` 原子锁 + 排队等锁 + SKIP 哨兵),跨进程(CLI/MCP/hook)同写不覆盖丢更新
28
+ 装了什么:
24
29
 
25
- ## 安装
30
+ | 宿主 | hook | MCP | skill |
31
+ |---|---|---|---|
32
+ | claude-code | `~/.claude/settings.json` hooks | `mcpServers.abs` (stdio) | `~/.claude/skills/abs-agent-brain-sync/` |
33
+ | codex | `~/.codex/hooks.json` | config.toml `[mcp_servers.abs]` | `~/.codex/skills/` |
34
+ | opencode | `~/.config/opencode/plugins/abs.ts` | opencode.json mcp.abs | skills/ |
35
+ | pi | `~/.pi/agent/extensions/abs.ts` | extension 内桥接 | skills/ |
36
+
37
+ - **幂等**:重复安装 = 更新,写入前自动备份
38
+ - **共存**:追加式合并,不会顶掉你这个事件上的其它 hook
39
+ - 装完**重启宿主**才生效
26
40
 
27
- ### 方式一:npm 全局安装(产品模式,推荐)
41
+ 从源码跑(开发用):
28
42
 
29
43
  ```bash
30
- npm install -g @fanchao8609/agent_brain_sync
31
- abs install # 交互式选智能体(或 --agent 指定)
44
+ git clone <repo-url> && cd agent_brain_sync
45
+ npm install && npm link # 之后全局就有 abs
32
46
  ```
33
47
 
34
- ### 方式二:从源码(开发)
48
+ ---
49
+
50
+ ## 怎么用
51
+
52
+ ### 项目里开一次
35
53
 
36
54
  ```bash
37
- git clone <repo> && cd <repo> && npm install
38
- node bin/abs.js install # 或先 npm link 使 `abs` 全局可用
55
+ cd 你的项目
56
+ abs init # 建 .brain/ 图谱,只需一次
39
57
  ```
40
58
 
41
- ### 安装到宿主(hook + MCP + skill)
59
+ ### 日常命令
42
60
 
43
61
  ```bash
44
- abs install # 全部: claude-code codex opencode pi
45
- abs install --agent claude-code # 只装 Claude Code (MCP+hook+skill)
46
- abs install --agent claude-code --no-mcp # 只 hook+skill
62
+ abs load # 开机读状态(路线 + 看板 + 最近流水)
63
+ abs todo # 看板 Today / In Progress / Blocked / Done
64
+
65
+ abs task start TASK-1 --note "要做什么"
66
+ abs task note TASK-1 --note "改到 X 文件 L40" # 实时断点
67
+ abs task blocked TASK-1 --note "卡在哪"
68
+ abs task done TASK-1
69
+
70
+ abs note "一句话经验" --tags 坑,docker # 经验暂存 → sources/
71
+ abs log "完成 X" # 记一行流水;abs log 无参 = 查看
72
+ abs query <词> # 检索图谱(多词 OR)
73
+ abs status # 当前项目 + 图谱概要
74
+ abs lint # 体检:死链/孤岛/超尺寸/堆积
75
+ ```
76
+
77
+ ### 工作流
78
+
79
+ - **hook 自动**:宿主生命周期事件写技术流水到 `~/.abs/log/`
80
+ - **实时层(你/AI 手动)**:任务和经验在边界处立刻用 `abs task` / `abs note` 落盘
81
+ - **收尾层**:`abs wrapup` 在 Stop 时快照未完成任务;下个会话开头对账 todo、沉淀经验、修 index
82
+
83
+ ---
47
84
 
48
- abs uninstall --agent claude-code # 卸载(只删 abs 装的,保留其它共存 hook)
49
- abs uninstall # 全部
85
+ ## 更新
86
+
87
+ ```bash
88
+ abs update
50
89
  ```
51
90
 
52
- 安装内容:
53
- | 宿主 | hook | MCP | skill |
54
- |---|---|---|---|
55
- | claude-code | `~/.claude/settings.json` hooks(与 moshi-hook 等**共存追加**,不覆盖) | settings.json `mcpServers.abs` (stdio) | `~/.claude/skills/abs-agent-brain-sync/` |
56
- | codex | `~/.codex/hooks.json` | config.toml `[mcp_servers.abs]` | `~/.codex/skills/` |
57
- | opencode | `~/.config/opencode/plugins/abs.ts` | opencode.json mcp.abs | skills/ |
58
- | pi | `~/.pi/agent/extensions/abs.ts` | extension 内桥接 | skills/ |
91
+ 查 npm 最新版 → 升级 → 自动重刷四个宿主的 hook/skill(hook 里烧的是绝对路径,升级后必须重装,`abs update` 帮你做了)。完事重启宿主。
92
+
93
+ 手动方式:
59
94
 
60
- 幂等:重复安装=更新;写入前自动备份;卸载只删 abs 的条目、保留其它共存 hook。
95
+ ```bash
96
+ npm i -g @fanchao8609/agent_brain_sync@latest
97
+ abs install # 重新刷 hook/skill
98
+ ```
61
99
 
62
- ## 项目里用
100
+ ---
101
+
102
+ ## 卸载
63
103
 
64
104
  ```bash
65
- abs init # 项目根建 .brain/ 图谱(一次)
66
- abs load # 开机读状态(index 路线 + todo 看板 + 最近 log)
67
- abs todo # 看板(Today/Backlog/Blocked/Done)
68
- abs task start TASK-1 --note "做什么" # 登记(幂等)
69
- abs task note TASK-1 --note "改到X文件L40" # 实时断点(↳ 断点: 行,幂等)
70
- abs task blocked TASK-1 --note "卡点原因" # 碰壁移 Blocked
71
- abs task done TASK-1 # 完成归位 Done
72
- abs note "经验一句话" --tags 坑,docker # 经验实时暂存 → sources/
73
- abs log "完成X:…" # 记一行工作成果流水;abs log 无参=查看 log.md
74
- abs query <词> # 检索图谱(多词 OR)
75
- abs lint # 图谱体检(死链/孤岛/超尺寸/堆积/index 漏列)
76
- abs status # 当前项目 + 图谱概要
105
+ abs uninstall # 全部宿主
106
+ abs uninstall --agent pi # 只卸 pi
107
+ npm uninstall -g @fanchao8609/agent_brain_sync
77
108
  ```
78
109
 
79
- 实时化分工:**hook 自动记技术流水;任务/经验经 CLI/MCP 实时落盘(每个任务边界立即调);
80
- 深提炼(sources→concepts)归收尾自觉层,工具不替你判断什么值得沉淀。** 详见 `skill/SKILL.md`。
110
+ 只删 abs 自己装的条目,**保留其它共存 hook**。
81
111
 
82
- ## 核心能力
112
+ **注意**:卸载**不会**删项目里的 `.brain/`——那是你的知识资产,要删自己 `rm -rf .brain`。
83
113
 
84
- - **并发写保护(lock)**: `.brain` 是"读-改-整写回",跨进程并发会互相覆盖。`src/lock.js` 用同目录 `.lock` 文件 `open('wx')` 原子抢占 + 排队等锁(预算 30s,指数退避)+ `SKIP` 哨兵,把 todo/index/log 的写串行化,避免丢失更新。
85
- - **统一读写收口(brainio)**: `src/brainio.js` 提供 `readBrain / writeBrain / appendBrain / createBrainFile`——所有需读写 .brain 文档的地方统一走它,写自动带 lock 防并发(新代码遵循此入口)。
86
- - **收尾自动化**: Stop 时 hook 在 `~/.abs/log/wrapup.log` 留 wrapup 提醒;下会话开头走"收尾循环"(对账 todo / 沉淀经验 / 修 index/log)。
87
- - **多宿主共存**: install 分区合并追加,不会顶掉同事件的其它 hook(如 moshi-hook)。
114
+ ---
88
115
 
89
116
  ## 开发
90
117
 
91
118
  ```bash
92
- npm test # 全量 110+ 单测(四层: CLI/install/MCP/hook + lock/brainio)
93
- npm run pack:check # 预览 npm 发布产物(files 白名单)
119
+ npm test # 110+ 单测(node:test,零外部测试依赖)
120
+ npm run pack:check # 预览 npm 发布产物
94
121
  ```
95
122
 
96
123
  ## 目录
@@ -98,15 +125,17 @@ npm run pack:check # 预览 npm 发布产物(files 白名单)
98
125
  ```
99
126
  agent_brain_sync/
100
127
  ├── bin/abs.js CLI 入口
101
- ├── bin/mcp.js MCP server (stdio, 官方 SDK, 窄工具面)
128
+ ├── bin/mcp.js MCP server (stdio)
102
129
  ├── src/index.js 图谱定位(向上找最近 .brain/)
103
- ├── src/lock.js .brain 并发写保护(原子锁 + 排队 + SKIP)
104
- ├── src/brainio.js 统一读写收口(readBrain/writeBrain/appendBrain)
130
+ ├── src/lock.js 并发写保护(原子锁 + 排队 + SKIP)
131
+ ├── src/brainio.js 统一读写收口
105
132
  ├── src/todo.js todo.md 分区读写
106
- ├── src/store.js CLI 命令实现 (init/load/todo/task/log/query/lint/status/…)
133
+ ├── src/store.js CLI 命令实现
107
134
  ├── src/hosts.js 四宿主接入定义
108
- ├── src/install.js 安装/卸载向导(分区共存合并)
109
- ├── hooks/event.sh hook 模板(纯触发 → 技术日志 + Stop wrapup 提醒)
110
- ├── skill/SKILL.md 技能(安装到各智能体)
111
- └── test/ 单测(node:test,零外部测试依赖)
135
+ ├── src/install.js 安装/卸载(分区共存合并)
136
+ ├── hooks/event.sh hook 模板
137
+ ├── skill/SKILL.md 技能(装到各智能体)
138
+ └── test/ 单测
112
139
  ```
140
+
141
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanchao8609/agent_brain_sync",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "agent-brain-sync: 跨会话 AI 编码记忆 — hook 纯触发 + CLI/MCP 读写 .brain markdown 图谱, 防并发写保护。",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/skill/SKILL.md CHANGED
@@ -103,6 +103,11 @@ monorepo 若多个子包各自独立交付,可各建一份 `.brain/`;横向
103
103
  **todo 不是收尾仪式,是干活中随改随写的活看板。** 每个任务边界立即更新,和 git commit
104
104
  同一个反射,别等收尾。用工具(MCP `abs_task` / CLI `abs task`):
105
105
 
106
+ > **写操作优先 MCP,不要用 `bash` 跑 `abs`。** 实测:MCP 单次 ~2ms(server 常驻),
107
+ > CLI 单次 27ms(其中 20ms 是每次起 node 进程的固定开销,读写本身仅 3ms)。
108
+ > 一轮发多条命令时差距明显。CLI 留给「人手动查看看板」,agent 读写走 MCP。
109
+ > 详见 [[perf-fixed-overhead]]。
110
+
106
111
  | 时机 | 动作 |
107
112
  |---|---|
108
113
  | 认领新任务 | `abs task start <id> --note "做什么"` |
package/src/wrapup.js CHANGED
@@ -18,6 +18,25 @@ export function wrapupLogPath() {
18
18
  // 同项目两次快照的最小间隔(秒)。agent_end 会逐 turn 触发, 无变化时不刷屏。
19
19
  export const WRAPUP_MIN_INTERVAL_MS = 5 * 60 * 1000;
20
20
 
21
+ // wrapup.log 轮转阈值。只留 .1 一层: 排查/Rebuild 只靠每个 proj 的最近一块,
22
+ // 旧块是死重量(parseWrapup 用 byProj.set 覆盖, 前面的块永远不会被读到)。
23
+ export const WRAPUP_MAX_BYTES = 1024 * 1024; // 1 MiB
24
+
25
+ /** 超阈值则轮转为 .1。放在 appendWrapup 里 → CLI/MCP/hook 三条路径都覆盖。 */
26
+ async function rotateIfNeeded(p) {
27
+ const max = Number(process.env.ABS_WRAPUP_MAX_BYTES || WRAPUP_MAX_BYTES);
28
+ let st;
29
+ try { st = await fs.stat(p); } catch { return; }
30
+ if (!Number.isFinite(max) || st.size <= max) return;
31
+ // 先把当前内容落成 .1(覆盖旧 .1), 再截断;失败则不动, 不让轮转本身丢数据
32
+ try {
33
+ await fs.rename(p, p + '.1');
34
+ } catch {
35
+ return;
36
+ }
37
+ await fs.writeFile(p, `[${localStamp()}] wrapup 轮转: 原文件 ${st.size} bytes > ${max}, 已移入 wrapup.log.1\n`, 'utf8').catch(() => {});
38
+ }
39
+
21
40
  /** 从 todo 文本/快照块提取任务清单。兼容顶层(todo.md `- [ ]`)与缩进(快照 ` - [ ]`)两种行。
22
41
  * body = 去掉 `- [ ]` 前缀、`(认领|完成 date)` 标注后的核心文本。bp 去掉 `↳ 断点|卡点: ` 前缀。
23
42
  * Done 区(## Done 下)不采。返回 [{ body, bp }],bp 为附属断点数组(或空)。 */
@@ -102,6 +121,8 @@ export async function appendWrapup(root) {
102
121
  await fs.mkdir(join(p, '..'), { recursive: true });
103
122
  const todo = await readTodo(root); // readTodo 幂等迁移,拿到权威内容
104
123
  const tasks = extractOpenTasks(todo);
124
+ // 轮转在写前做:否则文件无上限增长(只追加不清理,旧块永远读不到=死重量)
125
+ await rotateIfNeeded(p);
105
126
  let prev = '';
106
127
  try { prev = await fs.readFile(p, 'utf8'); } catch { /* 尚无文件 */ }
107
128
  const snap = parseWrapup(prev);