@fanchao8609/agent_brain_sync 1.8.2 → 1.8.4
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,78 @@ 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
|
-
|
|
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
|
+
if (!out.length) {
|
|
43
|
+
// 包内一个 skill 都没找到 = 安装树与代码版本不一致(半升级 / 旧布局 / 打包漏文件)。
|
|
44
|
+
// 不静默装 0 个: 曾实测新版代码遇扁平旧布局 → out=[] → 一句不说就什么都不装,
|
|
45
|
+
// 而旧版代码遇新布局只报一个当前版本根本不存在的路径(ENOENT skill/SKILL.md), 把人引去查源码。
|
|
46
|
+
const v = (() => { try { return JSON.parse(fsSync.readFileSync(join(ABS_DIR, 'package.json'), 'utf8')).version; } catch { return 'unknown'; } })();
|
|
47
|
+
const flat = fsSync.existsSync(join(SKILL_ROOT, 'SKILL.md'));
|
|
48
|
+
throw new Error(
|
|
49
|
+
`本包内没有可安装的 skill(${SKILL_ROOT}),安装树与代码版本不一致(当前 ${v})。\n` +
|
|
50
|
+
(flat
|
|
51
|
+
? ' 检测到旧版扁平布局 skill/SKILL.md,本版要求 skill/<名称>/SKILL.md。\n'
|
|
52
|
+
: ' skill/ 目录缺失或不含任何 <名称>/SKILL.md。\n') +
|
|
53
|
+
' 修复: npm i -g @fanchao8609/agent_brain_sync@latest && abs install(幂等,可安全重跑)',
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
})();
|
|
58
|
+
// 主 skill(会话开场加载的那个)。它也只是 ALL_SKILLS 的一员,此处仅用于告警比对。
|
|
59
|
+
const SKILL_SOURCE = join(SKILL_ROOT, 'abs-agent-brain-sync', 'SKILL.md');
|
|
25
60
|
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
61
|
+
/** 安装全部 skill 到该宿主。收口在此:四处安装点共用 —— 新增 skill 只改
|
|
62
|
+
* skill/ 目录,本函数与调用方都不动(避免「改一份不算改」)。返回步骤行。 */
|
|
28
63
|
async function installSkills(agentKey) {
|
|
29
64
|
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'));
|
|
65
|
+
const root = join(hostSkillDir(agentKey), '..');
|
|
66
|
+
for (const s of ALL_SKILLS) {
|
|
67
|
+
const t = join(root, s.name, 'SKILL.md');
|
|
68
|
+
await atomicWrite(t, await fs.readFile(s.src, 'utf8'));
|
|
36
69
|
steps.push(`✓ skill → ${t}`);
|
|
37
70
|
}
|
|
38
71
|
return steps;
|
|
39
72
|
}
|
|
40
73
|
|
|
74
|
+
/** 卸载该宿主的全部 skill(主 + 附带)。与 installSkills 同源同规则。
|
|
75
|
+
* 曾经的坑: 只有 claude-code 删了附带 skill,其余三宿主留下 abs-bug-hunter/ 残留。
|
|
76
|
+
*/
|
|
77
|
+
async function uninstallSkills(agentKey) {
|
|
78
|
+
const steps = [];
|
|
79
|
+
const root = join(hostSkillDir(agentKey), '..');
|
|
80
|
+
for (const s of ALL_SKILLS) {
|
|
81
|
+
const d = join(root, s.name);
|
|
82
|
+
await fs.rm(d, { recursive: true, force: true });
|
|
83
|
+
steps.push(`✓ skill 已删除 → ${d}`);
|
|
84
|
+
}
|
|
85
|
+
return steps;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
41
89
|
/**
|
|
42
90
|
* 本包的稳定入口路径解析(mcp.js / abs.js 通用)。
|
|
43
91
|
*
|
|
@@ -512,10 +560,7 @@ async function uninstallClaudeCode() {
|
|
|
512
560
|
await fs.rm(join(homedir(), '.abs', 'hooks', 'claude-code'), { recursive: true, force: true });
|
|
513
561
|
steps.push(`✓ ~/.abs/hooks/claude-code/ (本 agent hook 脚本) 已删除`);
|
|
514
562
|
// 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(", ")})`);
|
|
563
|
+
steps.push(...await uninstallSkills('claude-code'));
|
|
519
564
|
return steps;
|
|
520
565
|
}
|
|
521
566
|
|
|
@@ -640,8 +685,7 @@ async function uninstallCodex() {
|
|
|
640
685
|
steps.push(`✓ MCP 已从 ${mcpP} 移除`);
|
|
641
686
|
}
|
|
642
687
|
} catch {}
|
|
643
|
-
await
|
|
644
|
-
steps.push(`✓ skill 已删除`);
|
|
688
|
+
steps.push(...await uninstallSkills('codex'));
|
|
645
689
|
return steps;
|
|
646
690
|
}
|
|
647
691
|
|
|
@@ -768,8 +812,7 @@ async function uninstallOpenCode() {
|
|
|
768
812
|
await atomicWrite(mcpP, JSON.stringify(cfg, null, 2));
|
|
769
813
|
steps.push(`✓ MCP 已从 ${mcpP} 移除`);
|
|
770
814
|
}
|
|
771
|
-
await
|
|
772
|
-
steps.push(`✓ skill 已删除`);
|
|
815
|
+
steps.push(...await uninstallSkills('opencode'));
|
|
773
816
|
return steps;
|
|
774
817
|
}
|
|
775
818
|
|
|
@@ -801,8 +844,7 @@ async function uninstallPi() {
|
|
|
801
844
|
const steps = [];
|
|
802
845
|
await fs.rm(join(hostConfigRoot('pi'), 'agent', 'extensions', 'abs.ts'), { force: true });
|
|
803
846
|
steps.push(`✓ extension 已删除`);
|
|
804
|
-
await
|
|
805
|
-
steps.push(`✓ skill 已删除`);
|
|
847
|
+
steps.push(...await uninstallSkills('pi'));
|
|
806
848
|
const mcpP = join(hostConfigRoot('pi'), 'agent', 'mcp.json');
|
|
807
849
|
const cfg = await readJson(mcpP, { strict: false });
|
|
808
850
|
if (cfg === null) {
|
|
File without changes
|