@akasha-book/gate 1.2.4 → 1.3.1
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 +22 -42
- package/cordis.patch.yml +4 -2
- package/index.js +142 -48
- package/package.json +27 -15
package/README.md
CHANGED
|
@@ -1,49 +1,29 @@
|
|
|
1
|
-
# @akasha-
|
|
1
|
+
# @local/akasha-gate
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
阿卡夏之书门控 v1.2 —— 把「可机检的纪律」做成硬约束(设计稿 §10 投影律)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- **v1.2.2(2026-10-09)**:新增**自我层注入** `akasha:self`(order 699,排在用法条之前)——每会话自动核对「我是谁」:渲染时读 canon 中 tag『自我』的当前条目(canon-self-concept / canon-address-layers / canon-memory-auto-record…),每条截到句界(≤200 字)压缩注入;读不到 / 空域 → 极简兜底,永不抛;降级/恢复切换落线 `gate-self-fallback` / `gate-self-recovered`,`gate-armed` 增记 `selfSource` / `selfOrder`。
|
|
6
|
+
- **v1.2(2026-10-07 复查修复)**:重定向判定排除 JS 箭头(`=>`)与 `2>&1`(`(?<![=\-])>(?![&=])`)——修复前只读 `node -e` 探针(含 `=>{`)被误拦;带/无空格真重定向仍拦(自检哨兵)。
|
|
6
7
|
|
|
7
|
-
- ① `tools.guard`:拒绝 `edit` / `write` / `apply_patch`
|
|
8
|
-
-
|
|
9
|
-
- ② `systemPrompt.section`(name `akasha:protocol`,order 700):**渲染时读库**——`text`
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
8
|
+
- ① `tools.guard`:拒绝 `edit` / `write` / `apply_patch` 对 `akasha\data\` 的直写;拒绝 `pwsh` / `bash` 命令里对 `akasha\data` 的写操作(Set-Content / Add-Content / Out-File / Remove-Item / Copy-Item / `del` / 重定向 等)。数据必须经校验写入:`akasha` CLI / `mcp__akasha__*`。
|
|
9
|
+
- **已知边界(v0 有意为之)**:门控防「顺手直改」,不防刻意绕过(例如 `node -e` 脚本内写文件)——那是安全边界的活,不属于本层承诺。见设计稿 §10「只对可机检项承诺必定」。
|
|
10
|
+
- ② `systemPrompt.section`(name `akasha:protocol`,order 700):**渲染时读库**——`text` 传函数,官方 `dsh-system-prompt` 在组装时求值(`lib/index.js:342`),读 `canon-akasha-usage` 的**当前版本**(`currentRecords` 取链尾,含 `-rN`);**改用法 = `revise canon-akasha-usage`,下一次组装即生效**(无需重启/改码);读库失败回退本文件内置同文兜底(渲染永不抛)。
|
|
11
|
+
- 记录:`H:\Harness\akasha\logs\hooks.jsonl`(`gate-armed`〔含 `usageSource` / `selfSource`: library|fallback〕/ `gate-denied` / `prompt-change`〔只跟结构变更〕/ `gate-usage-fallback` / `gate-usage-recovered` / `gate-self-fallback` / `gate-self-recovered`)。
|
|
12
|
+
- 自测:`node selftest.mjs`(48 断言,桩 ctx + 真库文本 + 不存在目录回退 + 自我层三路,不需要宿主)。
|
|
13
|
+
- 绕过:`plugin_manager set_bundle` → `@local/akasha-gate` → `enabled:false`(或改本包 config)。
|
|
14
|
+
- 版本纪律:**替换已安装包需要重启才载入新 JS 代**(官方语义)。v1.0.1 修复命令分支路径判定(`startsWith` → `includes`);**v1.1.0 起注入改为库驱动**(自举缺口修复,2026-10-07);**v1.1.1**:库驱动降级/恢复的切换观测线(`gate-usage-fallback` / `gate-usage-recovered`,仅切换时落一行)+ `prompt-change` 语义注记(**只跟结构变更**,文本漂移不触发)。
|
|
14
15
|
|
|
15
|
-
## 打包 /
|
|
16
|
+
## 打包 / 安装
|
|
16
17
|
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
```powershell
|
|
19
|
+
cd H:\Harness\dsh-akasha-gate
|
|
20
|
+
F:\h\all\Nodejs\npm.cmd pack
|
|
21
|
+
# 然后:plugin_manager install_bundle <tgz 绝对路径>(新 bundle 会 HMR 热生效)
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
兼容声明见 manifest 的 `dsh.compatibility.dshReleases`:**0.2.0-rc.2 = compatible**(本机实测运行),
|
|
29
|
-
`0.2.1-alpha.1` / `0.2.1-alpha.2` 尚未实测 ⇒ 按契约如实写 `unknown`(不猜、不吹)。
|
|
30
|
-
|
|
31
|
-
| 证据层 | 状态 | 依据 |
|
|
32
|
-
|---|---|---|
|
|
33
|
-
| 静态契约(manifest / Bundle Patch / 许可证 / 入口 ID) | **verified** | 官方 `build-dsh-plugin` 审计:静态分见本包审计输出;入口 ID 为插件自有,不 disable/replace 任何 `@deepseek-ai/*` |
|
|
34
|
-
| 单元与边界测试(`npm test`) | **verified** | `node selftest.test.mjs` 全绿;覆盖 malformed 输入、并发/节流、replay 一致性(见该文件断言) |
|
|
35
|
-
| 一次性 Profile 安装·启动·卸载(E3) | **verified** | 2026-10-10 一次性 DSH_HOME 实跑:install → cold start(HTTP 就绪)→ stop → uninstall → `--dump-config` 逐字回到基线;dsh 0.2.0-rc.2;证据见同目录 `EVIDENCE.json` |
|
|
36
|
-
| 真实 Profile 运行 | **verified(本机)** | 桌面端 0.2.0-rc.2 实跑;**他人机器 unverified**(未做外部验收) |
|
|
37
|
-
| 独立安全审计 / 公开分发(E5) | **unverified** | 未做独立审计;分发前应重评 |
|
|
38
|
-
|
|
39
|
-
**下一道门(next gate)**:① 在 0.2.1-alpha.x 上按同一套用例复测(一次性 DSH_HOME),把 `unknown` 改为精确结论(`compatible` 或 `incompatible`);
|
|
40
|
-
② 提交 DSH STORE 上架申请(monorepo 子路径:`tree/main/plugins/<name>`)并跟进机器人预检。
|
|
41
|
-
若任一版本复测失败,该版本标注为 `blocked`(不兼容)并保持其余版本声明不动。
|
|
42
|
-
|
|
43
|
-
**权限 / 非目标 / 边界(permissions · non-goals · boundaries)**
|
|
44
|
-
- 读取:无(不读库文件);写入:仅追加门控日志行(
|
|
45
|
-
`logs/hooks.jsonl` 的 `gate-armed` / 降级切换线)。核心职责是**拦**(拒绝未经校验写入数据目录的工具调用),
|
|
46
|
-
自身不写数据文件。系统提示注入段(`akasha:protocol` / `akasha:self`)为**渲染时读库**,读失败回退兜底、不抛。
|
|
47
|
-
- **统一非目标(non-goals)**:不修改 DSH 核心与官方包;不替换、禁用或遮蔽任何官方组件;不写真实 Profile(测试一律用系统临时目录);
|
|
48
|
-
不在日志/输出里暴露凭据、完整用户文件或注入上下文。
|
|
49
|
-
- **测试隔离**:所有自测只使用 `os.tmpdir()` 下的临时目录;不读写真实库(`~/.akasha`)与真实会话档案。
|
|
24
|
+
|
|
25
|
+
## 源与许可(Source & License)
|
|
26
|
+
|
|
27
|
+
- 源仓库:https://github.com/Ersith/akasha-book
|
|
28
|
+
- 本版本固定提交(pinned commit):`5a55099586cfae4e7511ba433eaf202455d81c30`
|
|
29
|
+
- 许可证:MIT(见仓库根 LICENSE)
|
package/cordis.patch.yml
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
- insert:
|
|
2
2
|
- id: akasha-gate
|
|
3
|
-
name: '@akasha-
|
|
3
|
+
name: '@local/akasha-gate'
|
|
4
4
|
config:
|
|
5
|
-
|
|
5
|
+
log: 'H:\Harness\akasha\logs\hooks.jsonl'
|
|
6
|
+
dataDir: 'H:\Harness\akasha\data'
|
|
7
|
+
akashaDir: 'H:\Harness\akasha'
|
|
6
8
|
sectionOrder: 700
|
package/index.js
CHANGED
|
@@ -40,11 +40,135 @@ const AGENT_TOOLS = new Set(['codex_exec', 'codex_thread_start', 'codex_thread_r
|
|
|
40
40
|
// 2026-10-07 复查:重定向判定排除 JS 箭头(`=>`)与 `2>&1`——`(?<![=\-])` 挡 `=>`/`->`,`(?![&=])` 挡 `>&`;
|
|
41
41
|
// 曾因旧规则 `>\s*[^\s|]` 误拦只读探针命令(node -e 的 `=>{`)。`>>` 保留(真追加重定向)。
|
|
42
42
|
// 2026-10-10 人读复查补:**中文写动词**(委派型 prompt 常用"删掉/追加/写入/改写"),原先只认英文与 cmdlet。
|
|
43
|
+
// 2026-10-10 假阳性修复:shell 命令的写构造判定(收窄)——只认重定向与写/删类构造,
|
|
44
|
+
// 不再用广义写词表(那张表会让「只读命令里出现 data 路径」也被拒;当日实测被误拦一次)。
|
|
45
|
+
const WRITE_CMD = /(>>|(?<![=\-])>(?![&=])|Set-Content|Add-Content|Out-File|Remove-Item|Move-Item|Copy-Item|New-Item|Set-Item|\bdel\b|\brm\b|tee\b|sed -i)/i;
|
|
43
46
|
const WRITE_IDIOM = /(>>|(?<![=\-])>(?![&=])\s*[^\s|]|Set-Content|Add-Content|Out-File|Remove-Item|Move-Item|Copy-Item|New-Item|Set-Item|tee\b|sed -i|drop\b|delete\b|\bdel\b|追加|写入|改写|覆盖|替换|清空|删除|修改|编辑|append\b|overwrite\b|modify\b)/i;
|
|
44
47
|
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
+
// ── 规则层(2026-10-11,借鉴 CyberStrikeAI 的"有序规则 + 首命中 + 可试匹配";本改动**不改变**任何拒绝文案与判定条件)──
|
|
49
|
+
// 设计要点:① 规则**有序**,**首命中决定**;② 每条带 ruleId(进 gate-denied 日志,便于审计/复盘/回归);
|
|
50
|
+
// ③ 判定面扩展(B2):**参数里的所有字符串(含键名与嵌套)** + **百分号解码 ≤3 轮**;
|
|
51
|
+
// ④ 与 CLI `akasha/tools/gate-dry.mjs` **共用本工厂** ⇒ "试匹配"与"真拦截"永远同源。
|
|
52
|
+
export const RULES_VERSION = 'gate-rules/2026-10-11.1';
|
|
53
|
+
|
|
54
|
+
/** B2:递归收集值里的**所有字符串**(值 + 键名),限深限宽防药丸。 */
|
|
55
|
+
export function collectStrings(value, out = [], depth = 0) {
|
|
56
|
+
if (depth > 6 || out === null || out.length > 256) return out;
|
|
57
|
+
if (typeof value === 'string') { out.push(value); return out; }
|
|
58
|
+
if (Array.isArray(value)) { for (const v of value) collectStrings(v, out, depth + 1); return out; }
|
|
59
|
+
if (value && typeof value === 'object') {
|
|
60
|
+
for (const k of Object.keys(value)) { collectStrings(k, out, depth + 1); collectStrings(value[k], out, depth + 1); }
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** B2:百分号解码 ≤3 轮(无变化或解码失败即停)——挡 `%2e%2e%2f` 这类编码绕行。 */
|
|
66
|
+
export function decodeLayers(text, rounds = 3) {
|
|
67
|
+
let s = String(text ?? '');
|
|
68
|
+
for (let i = 0; i < rounds; i++) {
|
|
69
|
+
let d;
|
|
70
|
+
try { d = decodeURIComponent(s); } catch { break; }
|
|
71
|
+
if (d === s) break;
|
|
72
|
+
s = d;
|
|
73
|
+
}
|
|
74
|
+
return s;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* B2(**收窄**):只收集「路径类字段」的字符串值 —— 供写工具判定使用。
|
|
79
|
+
* 为什么不全量扫描:`edit` 的 new_string / 正文里**提到**数据路径,是合法写作(本机大量文档与脚本如此),
|
|
80
|
+
* 若按"出现即拦"会造成假阳性(2026-10-11 设计时自查发现,并已加对应用例)。
|
|
81
|
+
*/
|
|
82
|
+
const PATH_KEYS = /^(file_?paths?|paths?|target|destination|dest|files?|source|src)$/i;
|
|
83
|
+
export function collectPathArgs(value, key = '', out = [], depth = 0) {
|
|
84
|
+
if (depth > 6 || out.length > 64) return out;
|
|
85
|
+
if (typeof value === 'string') { if (PATH_KEYS.test(String(key))) out.push(value); return out; }
|
|
86
|
+
if (Array.isArray(value)) { for (const v of value) collectPathArgs(v, key, out, depth + 1); return out; }
|
|
87
|
+
if (value && typeof value === 'object') {
|
|
88
|
+
for (const k of Object.keys(value)) collectPathArgs(value[k], k, out, depth + 1);
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* 规则工厂:给定 dataDir 生成 `verdict(exec) → {deny, ruleId, tool, target, message}`。
|
|
95
|
+
* 纯函数式(不写日志、不碰宿主),保证 CLI 与门控判据一致。
|
|
96
|
+
*/
|
|
97
|
+
export function createGateRules({ dataDir }) {
|
|
98
|
+
const normPath = (p) => {
|
|
99
|
+
const r = resolve(String(p ?? ''));
|
|
100
|
+
return process.platform === 'win32' ? r.toLowerCase() : r;
|
|
101
|
+
};
|
|
102
|
+
const dataRoot = () => normPath(dataDir);
|
|
103
|
+
const isDataPath = (p) => {
|
|
104
|
+
const s = normPath(expandHome(String(p ?? '')));
|
|
105
|
+
const d = dataRoot();
|
|
106
|
+
return s === d || s.startsWith(d + sep);
|
|
107
|
+
};
|
|
108
|
+
const HOME_TOKENS = /(^|[\s'"=(:;|&])(?:~(?=[\\/])|\$HOME\b|\$\{HOME\}|\$env:USERPROFILE\b|%USERPROFILE%)/gi;
|
|
109
|
+
const mentionsDataDir = (text) => {
|
|
110
|
+
const expanded = decodeLayers(text).replace(HOME_TOKENS, (_m, pre) => pre + homedir());
|
|
111
|
+
const flat = expanded.replace(/[\\/]+/g, sep);
|
|
112
|
+
const d = dataRoot();
|
|
113
|
+
const probe = process.platform === 'win32' ? flat.toLowerCase() : flat;
|
|
114
|
+
return probe.includes(d + sep) || probe.includes(d);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const DENY_SUFFIX = '确需绕过请先停用 @akasha-book/gate。';
|
|
118
|
+
const rules = [
|
|
119
|
+
{
|
|
120
|
+
id: 'write-tool-data-path',
|
|
121
|
+
tools: WRITE_TOOLS,
|
|
122
|
+
check: (args) => {
|
|
123
|
+
for (const s of collectPathArgs(args)) {
|
|
124
|
+
if (s && isDataPath(s)) return { target: String(s) };
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
},
|
|
128
|
+
message: (tool, hit) => `阿卡夏门控:拒绝 ${tool} 直接写 ${hit.target}——数据必须经校验写入(akasha CLI / mcp__akasha__*),直改 JSONL 会污染 append-only 库。${DENY_SUFFIX}`,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 'shell-write-into-data',
|
|
132
|
+
tools: SHELL_TOOLS,
|
|
133
|
+
check: (args) => {
|
|
134
|
+
const command = String(args.command ?? args.script ?? '');
|
|
135
|
+
if (command && mentionsDataDir(command) && WRITE_CMD.test(decodeLayers(command))) return { target: 'akasha\\data(命令)' };
|
|
136
|
+
return null;
|
|
137
|
+
},
|
|
138
|
+
message: (tool) => `阿卡夏门控:拒绝 ${tool} 命令里对 akasha\\data 的写操作——请改走 akasha CLI / mcp__akasha__*。${DENY_SUFFIX}`,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: 'agent-prompt-write-into-data',
|
|
142
|
+
tools: AGENT_TOOLS,
|
|
143
|
+
check: (args) => {
|
|
144
|
+
const prompt = String(args.prompt ?? '');
|
|
145
|
+
if (prompt && mentionsDataDir(prompt) && WRITE_IDIOM.test(decodeLayers(prompt))) return { target: 'akasha\\data(委派 prompt)' };
|
|
146
|
+
return null;
|
|
147
|
+
},
|
|
148
|
+
message: (tool) => `阿卡夏门控:拒绝 ${tool} 的 prompt 里对 akasha\\data 的写操作——委派出去的子代理同样不得直改库;请改走 akasha CLI / mcp__akasha__*。`,
|
|
149
|
+
},
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
const verdict = (exec) => {
|
|
153
|
+
const name = String(exec?.name ?? '');
|
|
154
|
+
const args = exec?.arguments ?? {};
|
|
155
|
+
for (const r of rules) {
|
|
156
|
+
if (!r.tools.has(name)) continue;
|
|
157
|
+
const hit = r.check(args);
|
|
158
|
+
if (hit) return { deny: true, ruleId: r.id, tool: name, target: hit.target, message: r.message(name, hit) };
|
|
159
|
+
break; // 该工具的规则命中判空 ⇒ 放行(工具只归属一条规则)
|
|
160
|
+
}
|
|
161
|
+
return { deny: false };
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return { verdict, rules, isDataPath, mentionsDataDir, RULES_VERSION };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 已知边界(2026-10-10 立;2026-10-11 补充 B2 后的剩余面):
|
|
168
|
+
// · WSL 里同一物理文件可能以 `/mnt/<盘>/…` 出现,而本守卫只认配置里的 dataDir 形态(盘符路径)⇒ WSL 侧用挂载路径写入**拦不住**;
|
|
169
|
+
// · 编码绕行已部分收窄(百分号 ≤3 轮),但 base64/十六进制/环境变量拼接等**任意编码**仍可能绕过;
|
|
170
|
+
// · 只看"工具参数文本",**子进程内部**(脚本文件里再写数据)不在覆盖范围;
|
|
171
|
+
// · 这是**劝告层**,不是安全边界——完整清单见 docs/gate-boundaries.md。
|
|
48
172
|
|
|
49
173
|
// 读库失败时的兜底文本(与 canon-akasha-usage 初始版本同文;改兜底 = 升级本插件)。
|
|
50
174
|
const FALLBACK_SECTION = [
|
|
@@ -92,6 +216,13 @@ const SELF_TAIL = ['</akasha-self-data>', '详读:`node akasha.mjs show <id>`
|
|
|
92
216
|
const SELF_FALLBACK = [...SELF_HEAD, '(自我层暂不可读:库不可达——先跑 `akasha_kit`。)', ...SELF_TAIL].join('\n');
|
|
93
217
|
|
|
94
218
|
export function apply(ctx, config = {}) {
|
|
219
|
+
|
|
220
|
+
// A/B 实验开关(2026-10-10 用户解冻,见 docs/ab-experiment-design.md §6):
|
|
221
|
+
// abOff=true ⇒ **关闭臂**——本插件不注册任何守卫/注入/工具,只记一行观测;库文件与日志照旧(便于事后复盘)。
|
|
222
|
+
if (config.abOff === true) {
|
|
223
|
+
try { (ctx.logger?.info ?? (() => {}))('gate: abOff=true(A/B 关闭臂)——本插件不注册任何面'); } catch { /* 静默 */ }
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
95
226
|
const logPath = typeof config.log === 'string' && config.log.trim() !== '' ? expandHome(config.log) : DEFAULT_LOG;
|
|
96
227
|
// 路径用 Node 自己的 resolve(2026-10 复查)。此前把 '/' 一律换成 '\\' 再 join,
|
|
97
228
|
// 在 POSIX 上不再是绝对路径,require 核心库失败,用法条永远停在兜底。
|
|
@@ -181,52 +312,15 @@ export function apply(ctx, config = {}) {
|
|
|
181
312
|
}
|
|
182
313
|
};
|
|
183
314
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
};
|
|
188
|
-
const dataRoot = () => normPath(dataDir);
|
|
189
|
-
const isDataPath = (p) => {
|
|
190
|
-
const s = normPath(expandHome(String(p ?? '')));
|
|
191
|
-
const d = dataRoot();
|
|
192
|
-
return s === d || s.startsWith(d + sep);
|
|
193
|
-
};
|
|
194
|
-
// 命令文本:把正反斜杠都折成当前平台再比前缀(命令不等于路径)。
|
|
195
|
-
// 家目录简写(`~/`、`$HOME`、`${HOME}`、`$env:USERPROFILE`、`%USERPROFILE%`)先展开再比——
|
|
196
|
-
// 否则 `echo x >> ~/.akasha/data/canon.jsonl` 这类最常见写法比不中。
|
|
197
|
-
const HOME_TOKENS = /(^|[\s'"=(:;|&])(?:~(?=[\\/])|\$HOME\b|\$\{HOME\}|\$env:USERPROFILE\b|%USERPROFILE%)/gi;
|
|
198
|
-
const mentionsDataDir = (text) => {
|
|
199
|
-
const expanded = String(text ?? '').replace(HOME_TOKENS, (_m, pre) => pre + homedir());
|
|
200
|
-
const flat = expanded.replace(/[\\/]+/g, sep);
|
|
201
|
-
const d = dataRoot();
|
|
202
|
-
const probe = process.platform === 'win32' ? flat.toLowerCase() : flat;
|
|
203
|
-
return probe.includes(d + sep) || probe.includes(d);
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
// ① 数据目录写入守卫(同步、与注册顺序无关)。
|
|
315
|
+
// ① 数据目录写入守卫(同步、与注册顺序无关)——判据来自 createGateRules(**与 CLI `gate-dry` 同源**:
|
|
316
|
+
// 试匹配说"会拦"就一定拦、说"会放"就一定放;规则表与 ruleId 见模块顶部的 createGateRules)。
|
|
317
|
+
const gateRules = createGateRules({ dataDir });
|
|
207
318
|
ctx.tools.guard((exec) => {
|
|
208
319
|
try {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (target && isDataPath(target)) {
|
|
214
|
-
write({ kind: 'gate-denied', tool: name, target });
|
|
215
|
-
return `阿卡夏门控:拒绝 ${name} 直接写 ${target}——数据必须经校验写入(akasha CLI / mcp__akasha__*),直改 JSONL 会污染 append-only 库。确需绕过请先停用 @akasha-book/gate。`;
|
|
216
|
-
}
|
|
217
|
-
} else if (SHELL_TOOLS.has(name)) {
|
|
218
|
-
const command = String(args.command ?? args.script ?? '');
|
|
219
|
-
if (command && mentionsDataDir(command) && WRITE_IDIOM.test(command)) {
|
|
220
|
-
write({ kind: 'gate-denied', tool: name, target: 'akasha\\data(命令)' });
|
|
221
|
-
return `阿卡夏门控:拒绝 ${name} 命令里对 akasha\\data 的写操作——请改走 akasha CLI / mcp__akasha__*。确需绕过请先停用 @akasha-book/gate。`;
|
|
222
|
-
}
|
|
223
|
-
} else if (AGENT_TOOLS.has(name)) {
|
|
224
|
-
// 委派型工具:自然语言 prompt 里若同时出现数据目录与写动作词,同样按"写操作"拒绝(2026-10-10 补)
|
|
225
|
-
const prompt = String(args.prompt ?? '');
|
|
226
|
-
if (prompt && mentionsDataDir(prompt) && WRITE_IDIOM.test(prompt)) {
|
|
227
|
-
write({ kind: 'gate-denied', tool: name, target: 'akasha\\data(委派 prompt)' });
|
|
228
|
-
return `阿卡夏门控:拒绝 ${name} 的 prompt 里对 akasha\\data 的写操作——委派出去的子代理同样不得直改库;请改走 akasha CLI / mcp__akasha__*。`;
|
|
229
|
-
}
|
|
320
|
+
const v = gateRules.verdict(exec);
|
|
321
|
+
if (v.deny) {
|
|
322
|
+
write({ kind: 'gate-denied', tool: v.tool, target: v.target, ruleId: v.ruleId });
|
|
323
|
+
return v.message;
|
|
230
324
|
}
|
|
231
325
|
} catch { /* 守卫异常 → 放行 */ }
|
|
232
326
|
return undefined;
|
|
@@ -253,5 +347,5 @@ export function apply(ctx, config = {}) {
|
|
|
253
347
|
|
|
254
348
|
usageText(); // 播种 usageSource(首调不落切换线)
|
|
255
349
|
selfText(); // 播种 selfSource
|
|
256
|
-
write({ kind: 'gate-armed', pid: process.pid, dataDir, sectionOrder, selfOrder, akashaDir, usageSource: lastUsageSource, selfSource: lastSelfSource });
|
|
350
|
+
write({ kind: 'gate-armed', pid: process.pid, dataDir, sectionOrder, selfOrder, akashaDir, usageSource: lastUsageSource, selfSource: lastSelfSource, rulesVersion: RULES_VERSION });
|
|
257
351
|
}
|
package/package.json
CHANGED
|
@@ -1,24 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akasha-book/gate",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=18"
|
|
6
|
+
},
|
|
7
7
|
"type": "module",
|
|
8
|
-
"description": "
|
|
9
|
-
"exports": {
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
"description": "阿卡夏之书门控:数据目录写入守卫(规则工厂 + ruleId + 试匹配同源)+ 系统提示注入来源态约定(akasha:protocol)+ 自我层(akasha:self,每会话自动核对「我是谁」)",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./index.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"index.js",
|
|
14
|
+
"cordis.patch.yml",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
12
17
|
"dsh": {
|
|
13
18
|
"bundle": {
|
|
14
19
|
"patch": "./cordis.patch.yml"
|
|
15
|
-
},
|
|
16
|
-
"compatibility": {
|
|
17
|
-
"dshReleases": {
|
|
18
|
-
"0.2.0-rc.2": "compatible",
|
|
19
|
-
"0.2.1-alpha.1": "compatible",
|
|
20
|
-
"0.2.1-alpha.2": "compatible"
|
|
21
|
-
}
|
|
22
20
|
}
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"@deepseek-ai/dsh": "^0.2.0-rc.2",
|
|
24
|
+
"@deepseek-ai/cordis": "^4.0.4"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/Ersith/akasha-book.git",
|
|
30
|
+
"directory": "dsh-akasha-gate"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"test": "node selftest.test.mjs",
|
|
34
|
+
"check": "node --check lib/index.js"
|
|
23
35
|
}
|
|
24
36
|
}
|