@fanchao8609/agent_brain_sync 1.8.2 → 1.8.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
|
@@ -32,7 +32,11 @@ abs install --agent pi --no-mcp # 只装 hook + skill,不要 MCP
|
|
|
32
32
|
| claude-code | `~/.claude/settings.json` hooks | `mcpServers.abs` (stdio) | `~/.claude/skills/abs-agent-brain-sync/` |
|
|
33
33
|
| codex | `~/.codex/hooks.json` | config.toml `[mcp_servers.abs]` | `~/.codex/skills/` |
|
|
34
34
|
| opencode | `~/.config/opencode/plugins/abs.ts` | opencode.json mcp.abs | skills/ |
|
|
35
|
-
| pi | `~/.pi/agent/extensions/abs.ts` |
|
|
35
|
+
| pi | `~/.pi/agent/extensions/abs.ts` | `~/.pi/agent/mcp.json` `mcpServers.abs` | `~/.pi/agent/skills/` |
|
|
36
|
+
|
|
37
|
+
> **skill 规则**:`skill/` 下每个含 `SKILL.md` 的子目录 = 一个 skill,
|
|
38
|
+
> **目录名即安装名**(须与 frontmatter `name` 一致,否则 pi 会告警)。
|
|
39
|
+
> 新增 skill 只需建目录,无需改代码。
|
|
36
40
|
|
|
37
41
|
- **幂等**:重复安装 = 更新,写入前自动备份
|
|
38
42
|
- **共存**:追加式合并,不会顶掉你这个事件上的其它 hook
|
|
@@ -110,7 +114,7 @@ npm i -g @fanchao8609/agent_brain_sync@latest
|
|
|
110
114
|
abs install # 重新刷 hook/skill
|
|
111
115
|
```
|
|
112
116
|
|
|
113
|
-
> ⚠️ 改完源码(尤其 `skill
|
|
117
|
+
> ⚠️ 改完源码(尤其 `skill/*/SKILL.md`、`src/`)后**必须 `abs install --yes` 重扇出**,否则宿主还在跑旧副本 —— 版本号与代码会脱节。发布用 `npm version patch`(自动打 tag),别手改 `package.json` 的 version;发布后 `npm view` 有缓存延迟,必要时 `npm cache clean --force` 再验。
|
|
114
118
|
|
|
115
119
|
---
|
|
116
120
|
|
|
@@ -150,7 +154,7 @@ agent_brain_sync/
|
|
|
150
154
|
├── src/userconfig.js 使用者姓名配置(作者标记)
|
|
151
155
|
├── src/wrapup.js Stop 收尾快照/归档
|
|
152
156
|
├── hooks/event.sh hook 模板
|
|
153
|
-
├── skill
|
|
157
|
+
├── skill/<名称>/SKILL.md 技能(每个子目录 = 一个 skill,装到各智能体)
|
|
154
158
|
└── test/ 单测
|
|
155
159
|
```
|
|
156
160
|
|
package/package.json
CHANGED
package/src/install.js
CHANGED
|
@@ -14,30 +14,64 @@ import { HOSTS, hostByKey } from './hosts.js';
|
|
|
14
14
|
|
|
15
15
|
const ABS_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
16
16
|
const HOOK_TEMPLATE = join(ABS_DIR, 'hooks', 'event.sh');
|
|
17
|
-
const SKILL_SOURCE = join(ABS_DIR, 'skill', 'SKILL.md');
|
|
18
17
|
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
// ---- skill 包规则(单一规则,无特例)----
|
|
19
|
+
// skill/ 下**每个含 SKILL.md 的子目录**就是一个 skill,随包发布。
|
|
20
|
+
// 目录名 = 宿主 skills/ 下的安装目录名 = frontmatter 的 name(三者必须一致:
|
|
21
|
+
// pi 在目录名与 name 不一致时会告警)。
|
|
22
|
+
//
|
|
23
|
+
// 为什么全带 abs- 前缀:
|
|
24
|
+
// 1. 归属可辨 —— 带前缀才敢判「这是 abs 装的、可随 install 更新/卸载」;
|
|
25
|
+
// 不带前缀的副本可能是用户自己放的,卸载时不敢动。
|
|
26
|
+
// 2. 避开同名冲突 —— pi 同时扫 ~/.pi/agent/skills 与 ~/.agents/skills
|
|
27
|
+
// (pi 文档 Locations 一节),后者常有同名副本。两份同名实文件 → pi 报
|
|
28
|
+
// skill 冲突(实测: 曾装成 bug-hunter,与 ~/.agents/skills/bug-hunter 相撞)。
|
|
29
|
+
//
|
|
30
|
+
// 新增 skill: 建 skill/<名称>/SKILL.md 即可,无需改代码(原先写死一条,见旧注释 ponytail)。
|
|
31
|
+
const SKILL_ROOT = join(ABS_DIR, 'skill');
|
|
32
|
+
const ALL_SKILLS = (() => {
|
|
33
|
+
const out = [];
|
|
34
|
+
let entries = [];
|
|
35
|
+
try { entries = fsSync.readdirSync(SKILL_ROOT, { withFileTypes: true }); } catch { /* 无 skill/ 目录: 无 skill 可装 */ }
|
|
36
|
+
for (const e of entries) {
|
|
37
|
+
if (!e.isDirectory()) continue;
|
|
38
|
+
const src = join(SKILL_ROOT, e.name, 'SKILL.md');
|
|
39
|
+
if (!fsSync.existsSync(src)) continue; // 只认含 SKILL.md 的子目录
|
|
40
|
+
out.push({ name: e.name, src });
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
})();
|
|
44
|
+
// 主 skill(会话开场加载的那个)。它也只是 ALL_SKILLS 的一员,此处仅用于告警比对。
|
|
45
|
+
const SKILL_SOURCE = join(SKILL_ROOT, 'abs-agent-brain-sync', 'SKILL.md');
|
|
46
|
+
|
|
47
|
+
/** 安装全部 skill 到该宿主。收口在此:四处安装点共用 —— 新增 skill 只改
|
|
48
|
+
* skill/ 目录,本函数与调用方都不动(避免「改一份不算改」)。返回步骤行。 */
|
|
28
49
|
async function installSkills(agentKey) {
|
|
29
50
|
const steps = [];
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const t = join(base, '..', b.name, 'SKILL.md');
|
|
35
|
-
await atomicWrite(t, await fs.readFile(b.src, 'utf8'));
|
|
51
|
+
const root = join(hostSkillDir(agentKey), '..');
|
|
52
|
+
for (const s of ALL_SKILLS) {
|
|
53
|
+
const t = join(root, s.name, 'SKILL.md');
|
|
54
|
+
await atomicWrite(t, await fs.readFile(s.src, 'utf8'));
|
|
36
55
|
steps.push(`✓ skill → ${t}`);
|
|
37
56
|
}
|
|
38
57
|
return steps;
|
|
39
58
|
}
|
|
40
59
|
|
|
60
|
+
/** 卸载该宿主的全部 skill(主 + 附带)。与 installSkills 同源同规则。
|
|
61
|
+
* 曾经的坑: 只有 claude-code 删了附带 skill,其余三宿主留下 abs-bug-hunter/ 残留。
|
|
62
|
+
*/
|
|
63
|
+
async function uninstallSkills(agentKey) {
|
|
64
|
+
const steps = [];
|
|
65
|
+
const root = join(hostSkillDir(agentKey), '..');
|
|
66
|
+
for (const s of ALL_SKILLS) {
|
|
67
|
+
const d = join(root, s.name);
|
|
68
|
+
await fs.rm(d, { recursive: true, force: true });
|
|
69
|
+
steps.push(`✓ skill 已删除 → ${d}`);
|
|
70
|
+
}
|
|
71
|
+
return steps;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
41
75
|
/**
|
|
42
76
|
* 本包的稳定入口路径解析(mcp.js / abs.js 通用)。
|
|
43
77
|
*
|
|
@@ -512,10 +546,7 @@ async function uninstallClaudeCode() {
|
|
|
512
546
|
await fs.rm(join(homedir(), '.abs', 'hooks', 'claude-code'), { recursive: true, force: true });
|
|
513
547
|
steps.push(`✓ ~/.abs/hooks/claude-code/ (本 agent hook 脚本) 已删除`);
|
|
514
548
|
// skill
|
|
515
|
-
|
|
516
|
-
await fs.rm(skillDir, { recursive: true, force: true });
|
|
517
|
-
for (const b of BUNDLED_SKILLS) await fs.rm(join(skillDir, '..', b.name), { recursive: true, force: true });
|
|
518
|
-
steps.push(`✓ skill 已删除(含附带: ${BUNDLED_SKILLS.map((x) => x.name).join(", ")})`);
|
|
549
|
+
steps.push(...await uninstallSkills('claude-code'));
|
|
519
550
|
return steps;
|
|
520
551
|
}
|
|
521
552
|
|
|
@@ -640,8 +671,7 @@ async function uninstallCodex() {
|
|
|
640
671
|
steps.push(`✓ MCP 已从 ${mcpP} 移除`);
|
|
641
672
|
}
|
|
642
673
|
} catch {}
|
|
643
|
-
await
|
|
644
|
-
steps.push(`✓ skill 已删除`);
|
|
674
|
+
steps.push(...await uninstallSkills('codex'));
|
|
645
675
|
return steps;
|
|
646
676
|
}
|
|
647
677
|
|
|
@@ -768,8 +798,7 @@ async function uninstallOpenCode() {
|
|
|
768
798
|
await atomicWrite(mcpP, JSON.stringify(cfg, null, 2));
|
|
769
799
|
steps.push(`✓ MCP 已从 ${mcpP} 移除`);
|
|
770
800
|
}
|
|
771
|
-
await
|
|
772
|
-
steps.push(`✓ skill 已删除`);
|
|
801
|
+
steps.push(...await uninstallSkills('opencode'));
|
|
773
802
|
return steps;
|
|
774
803
|
}
|
|
775
804
|
|
|
@@ -801,8 +830,7 @@ async function uninstallPi() {
|
|
|
801
830
|
const steps = [];
|
|
802
831
|
await fs.rm(join(hostConfigRoot('pi'), 'agent', 'extensions', 'abs.ts'), { force: true });
|
|
803
832
|
steps.push(`✓ extension 已删除`);
|
|
804
|
-
await
|
|
805
|
-
steps.push(`✓ skill 已删除`);
|
|
833
|
+
steps.push(...await uninstallSkills('pi'));
|
|
806
834
|
const mcpP = join(hostConfigRoot('pi'), 'agent', 'mcp.json');
|
|
807
835
|
const cfg = await readJson(mcpP, { strict: false });
|
|
808
836
|
if (cfg === null) {
|
|
File without changes
|