@yottameta/yotta-memory 0.8.3 → 0.8.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # 更新日志
2
2
 
3
+ ## v0.8.5 (2026-08-29)
4
+
5
+ 安全修复(SkillHub 安全扫描发现高危,修复后三源同步升版):
6
+
7
+ - **MCP 命令执行入口封死**:MCP `distill` 不再接受 `--model`(`callTool` 在工具边界直接拒绝),远端智能体无法再借 MCP 在引擎主机执行任意命令。
8
+ - **MCP 任意路径读写封死**:MCP `export` / `import` 的 `out` / `src` 必须落在记忆库根内(新增 `resolveWithinRoot` 校验,防 `..` 穿越),库外路径直接拒绝,与「远程只能读写记忆」承诺对齐。
9
+ - **CLI 参数解析修复**:`--model` / `--subject` / `--reason` / `--merge` 此前被 valueOpts 消费但未写入 opts,导致 `distill --model` / `--subject` 实际不生效;本版补齐映射,CLI `distill --model` 现已真正走 `runDistillModel` 安全路径(`shell:false` + 允许清单)。
10
+ - **CLI distill 去 shell 注入**:`distill --model` 改走 `runDistillModel` —— `spawnSync(argv[0], argv.slice(1), { shell:false, windowsHide:true })` + `splitCommandArgv` 拆分 argv,彻底移除 shell 注入面;新增 `distillModelAllowlist`(环境变量 `YOTTA_DISTILL_MODELS` 或 `config.distill_models`,未配置时放行本地 CLI,但已无 shell 注入;MCP 层已直接禁 `--model`,不达此处)。
11
+ - 版本对齐:package.json / SKILL.md / CHANGELOG / 引擎 VERSION / 文档边界说明 = 0.8.5。
12
+ - 新增回归测试:`test/security-boundary.test.js`(MCP 禁 --model / export-import 限库内 / 合法操作仍可用,6 项断言)。
13
+ ## v0.8.4 (2026-08-29)
14
+
15
+ - 安装方式统一为四方式(对齐发布规范 §3.3.1):方式一 `npx -y @yottameta/yotta-memory --agent <name>` / `--dir <dir>`(推荐,走 npm 源);方式二 `git clone https://github.com/YottaMeta/yotta-memory.git`;方式三 GitHub Download ZIP;方式四 `bash install.sh --agent/--dir/--list`。移除 `npx skills` 与 `-g` 推荐;中英双 README 安装节同步。
16
+ - 版本对齐:package.json / SKILL.md / CHANGELOG / 引擎 VERSION / 测试断言 / README 锚点 = 0.8.4。
17
+ - 修复:SKILL.md / USER_GUIDE.md 安装命令改 `--agent <name>` 合规形式(`npx -y --package @yottameta/yotta-memory yotta-memory-install --agent <name>`),移除 `-g` 与 `npx skills` 推荐。
18
+ - 无功能变更(仅文档与版本同步)。
19
+
3
20
  ## v0.8.3 (2026-08-28)
4
21
 
5
22
  中英双语 README 对齐(老张拍板「英文门面 + 中文全档」):
package/README.md CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  > 📖 The user-facing operations manual lives in [USER_GUIDE.md](USER_GUIDE.md).
25
25
 
26
- > 🆕 **v0.8.3**: bilingual README alignment — README.md becomes the English facade (GitHub / npm / ClawHub homepage) and README.zh-CN.md carries the full Chinese doc; no functional changes.
26
+ > 🆕 **v0.8.5**: security hardening — MCP `distill` no longer accepts `--model`; MCP `export` / `import` paths are restricted to the memory root; CLI `distill --model` no longer shells out (allowlist-based).
27
27
 
28
28
  ## Core value
29
29
 
@@ -93,7 +93,7 @@ Each agent has a globally unique agent ID: it is the ownership key for private m
93
93
  - `maintain`: unified utility score (final score = confidence + usage + recency + type + structure) × weight; low-utility + over-age auto-archive; extreme low value listed as forget candidates (not really deleted by default; `--purge` deletes); `--dedup` dedup candidates; `--merge A,B` manual merge. Dry-run preview by default, `--apply` to execute; immutable / BOUND exempt; audit writes `.archive/audit-<date>.jsonl`.
94
94
  - `archive`: moves low-value old memory into `.archive/` by "unified utility score + age" (immutable excluded) so the store never grows without bound.
95
95
  - `feedback`: explicit usage feedback loop — useful → weight ×1.2 (cap 3.0) + confidence +0.05 + feedback_net +1; useless → weight ×0.8 (floor 0.2) + confidence −0.05 + feedback_net −1; `--undo` rolls back; audit writes `.archive/feedback-<date>.jsonl`.
96
- - `distill`: psychological-log distillation — statistical summary (type / age / heat / feedback) + topic profile (clustered by subject) + knowledge map (type → tags); optional `--model <cmd>` external model stdin→stdout refinement; output to `private/<owner>/distills/` or `facts/distills/`.
96
+ - `distill`: psychological-log distillation — statistical summary (type / age / heat / feedback) + topic profile (clustered by subject) + knowledge map (type → tags); optional `--model <cmd>` external model stdin→stdout refinement (local CLI only; MCP distill does not expose `--model`); output to `private/<owner>/distills/` or `facts/distills/`.
97
97
  - `explain`: view a single memory's utility components and archive / forget status decision.
98
98
  - `forget`: delete a single memory (by type-dir path or file name).
99
99
  - `reindex`: rebuild the index after manually editing `.md` files.
@@ -117,34 +117,40 @@ Each agent has a globally unique agent ID: it is the ownership key for private m
117
117
 
118
118
  ## Install
119
119
 
120
- Yuanyi ships as **CLI + skill** — the `yotta-memory` command reads/writes memory, and the skill teaches agents the workflow. Pick any method; skill files come from **npm**.
120
+ Yotta Memory ships as a **CLI + skill** pair: the `yotta-memory` command reads/writes the memory store, and the skill teaches agents the workflow. Pick any of the four methods below; the order is the recommended priority. Skill files always come from **npm** (GitHub can be slow without a proxy; npm supports mirrors).
121
121
 
122
- ### Method 1: npx skills (recommended, ecosystem-standard entry)
123
- ```bash
124
- npx skills add YottaMeta/yotta-memory
122
+ ### Method 1: npm one-liner (recommended)
123
+
124
+ ```text
125
+ # Optional China mirror: npm config set registry https://registry.npmmirror.com
126
+ npx -y --package @yottameta/yotta-memory yotta-memory-install --agent <agent-name> # install the skill to the agent's default user-level dir
127
+ npx -y --package @yottameta/yotta-memory yotta-memory-install --dir <your-skills-dir> # point to the skills dir itself (e.g. ~/.codex/skills)
125
128
  ```
126
- > Auto-installs the skill files into detected agents (Claude Code / Codex / Cursor / OpenCode and 78+ more). This installs only the skill instructions (SKILL.md etc.); to use the `yotta-memory` read/write commands you also need the CLI: `npm install -g @yottameta/yotta-memory` (see method 2).
127
129
 
128
- ### Method 2: npm direct install (CLI + skill)
129
- ```bash
130
- # domestic mirror (optional): npm config set registry https://registry.npmmirror.com
131
- npm install -g @yottameta/yotta-memory
132
- yotta-memory init # initialize the memory store
133
- yotta-memory-install -g # install the skill into all recognized agents (user level)
134
- yotta-memory-install --agent codex # install into one specific agent
130
+ - `--agent <name>` installs to that agent's default user-level directory; `--list` shows each agent's default directory.
131
+ - `--dir <path>` installs to the given directory; for agents not in the preset list, point `--dir` at their skills directory.
132
+ - If the mirror has not synced the new package (404): add `--registry=https://registry.npmjs.org/` (a proxy may be needed in China), or wait for the mirror cache.
133
+ - To read/write memories, also install the CLI: `npm install -g @yottameta/yotta-memory` (see the CLI usage section below).
134
+
135
+ ### Method 2: git clone (developers / git available)
136
+
137
+ ```text
138
+ git clone https://github.com/YottaMeta/yotta-memory.git <your-skills-dir>/yotta-memory
135
139
  ```
136
140
 
137
- > After global install both `yotta-memory` (read/write) and `yotta-memory-install` (installer) are on PATH. Prefer not to install globally? Run the installer one-shot: `npx -y --package @yottameta/yotta-memory yotta-memory-install -g`.
141
+ ### Method 3: GitHub Download ZIP (manual / no git)
138
142
 
139
- ### Method 3: install.sh / manual copy
140
- After obtaining the skill folder (`npm pack` unpack or `git clone`), enter the folder:
141
- ```bash
142
- bash install.sh -g # user level; bash install.sh --list shows all directories
143
- bash install.sh --agent codex # specific agent
144
- bash install.sh --dir /path/to/skills
143
+ On the GitHub repository `YottaMeta/yotta-memory`, click **Code → Download ZIP**, unzip it and put the `yotta-memory` folder into the agent's skills directory.
144
+
145
+ ### Method 4: install.sh (multi-agent one-liner script)
146
+
147
+ ```text
148
+ bash install.sh --agent <name> # install to the agent's default user-level directory
149
+ bash install.sh --dir <path> # install to the given directory
150
+ bash install.sh --list # list agents -> default directories
145
151
  ```
146
- You can also copy the whole `yotta-memory` folder into the target agent's skills directory (common locations via install.sh --list).
147
152
 
153
+ > Method 1 uses the npm registry (npmmirror / npmjs) and does not depend on GitHub; Methods 2/3 use GitHub and may fail without a proxy in China.
148
154
  ## Upgrade
149
155
 
150
156
  Two upgrade paths match the two install paths:
@@ -154,7 +160,7 @@ Two upgrade paths match the two install paths:
154
160
  npm i -g @yottameta/yotta-memory
155
161
  ```
156
162
 
157
- **Upgrade the skill**: rerun the install command you used originally (`npx skills add YottaMeta/yotta-memory` or `yotta-memory-install -g`) to overwrite the old skill folder.
163
+ **Upgrade the skill**: rerun your install command from the `## Install` section (e.g. `npx -y --package @yottameta/yotta-memory yotta-memory-install --agent <name>` or `bash install.sh --agent <name>`) to overwrite the old skill folder.
158
164
 
159
165
  > Upgrades only affect commands and skill files — **they never touch your stored memories** (memory is independent of the install, kept in its own directory).
160
166
 
@@ -244,7 +250,7 @@ Register the connection in the agent's MCP config (`url` + two headers):
244
250
  }
245
251
  ```
246
252
 
247
- Once connected, MCP tools (remember / recall / search / forget / archive / reindex / export / import / agent_info) read/write memory and confirm identity; management actions (init / config / token / lan / serve) are not exposed via MCP, and token management is never exposed remotely. `X-Agent-Id` must match the token's registered agent; read-partition rules are the same as the CLI (FACT public-readable, PREF / BOUND / COMMIT private).
253
+ Once connected, MCP tools (remember / recall / search / forget / archive / reindex / export / import / agent_info) read/write memory and confirm identity; management actions (init / config / token / lan / serve) are not exposed via MCP, and token management is never exposed remotely. MCP `export` / `import` paths are restricted inside the memory root, and MCP `distill` does not support `--model` (local CLI only). `X-Agent-Id` must match the token's registered agent; read-partition rules are the same as the CLI (FACT public-readable, PREF / BOUND / COMMIT private).
248
254
 
249
255
  ### Location persistence
250
256
 
package/README.zh-CN.md CHANGED
@@ -23,6 +23,8 @@
23
23
 
24
24
  > 📖 面向用户的操作手册见 [USER_GUIDE.md](USER_GUIDE.md)。
25
25
 
26
+ > 🆕 **v0.8.5**:安全加固——MCP `distill` 不再接受 `--model`;MCP `export` / `import` 路径限记忆库内;CLI `distill --model` 不再走 shell(改为允许清单)。
27
+
26
28
  > 🆕 **v0.8.2**:发布元数据修复——三次源重发带 `--name 元忆 yotta-memory`,修复 ClawHub 展示名缺失中文(原为裸 `yotta-memory`);无功能变更。
27
29
 
28
30
  > 🆕 **v0.8.1**:`view` 用户查看平台改为服务端分页(记忆多了一次只渲染当前页,页码上下页);`recall` 增加候选预过滤(语义检索前先粗筛候选集,命中集不变,记忆量大时不再逐条全量语义 / 模糊 / 编辑距离);公共 `index.json` 超过 5000 条时按年份分片(`index-<year>.json`),避免单文件膨胀。
@@ -51,7 +53,7 @@
51
53
  | **双级存储** | 用户级 `~/.yottamemory/`(跨项目)+ 项目级 `.yottamemory/`(随项目共享 / 交接)|
52
54
  | **检索与生命周期** | 语义检索(v0.8.0:同义词 / 拼音 / 字段加权 / 模糊,零依赖)+ 效用分融合排序;统一效用分(盖棺分)规则层自动归档 / 遗忘候选 / 去重(`maintain`,默认 dry-run),记忆库越用越精简 |
53
55
  | **越用越懂(v0.6.0)** | `profile` 画像聚合(零推断)+ `context` 开工上下文包(身份 / 画像 / 近期记忆 / 边界 / 承诺)+ SKILL「记忆守则」规则层,记忆随使用成长 |
54
- | **生态分发** | GitHub + npm 双源同步发布;npx skills / npm / install.sh 三种方式,覆盖 17+ 类智能体目录 |
56
+ | **生态分发** | GitHub + npm 双源同步发布;npx / git clone / Download ZIP / install.sh 四种安装方式,覆盖 17+ 类智能体目录 |
55
57
  | **便携记忆盘(随盘走)** | 记忆库即引擎:装在硬盘 / 主机上,插上即恢复全部记忆;引擎主机只需装 CLI 当存放点,无需装任何 AI 智能体 |
56
58
  | **局域网共享与自启** | 每智能体独立 token(Bearer + X-Agent-Id)鉴权、可吊销;`lan enable` 注册开机自启(Windows:优先计划任务,非管理员自动降级用户级 Startup 静默自启;Linux:systemd 用户单元,不可用时自动降级用户 crontab @reboot);MCP 工具集与 CLI 一致(8 个工具),管理动作不远程暴露 |
57
59
  | **本地 / 局域网双模式** | 本地 `serve --stdio` 零进程、按需拉起(无常驻);局域网 streamable HTTP 常驻——两种模式可并存、按需选用 |
@@ -134,7 +136,7 @@
134
136
  - **记忆库即引擎**:`serve` 把记忆目录挂成 MCP 服务,目录随盘走;引擎主机只需装 CLI 当存放点,无需装任何 AI 智能体。
135
137
  - **双模式可并存**:本地 `serve --stdio` 零进程(客户端按需拉起);局域网 streamable HTTP(默认 `0.0.0.0:8787`)+ 每智能体 token 鉴权。
136
138
  - **开机自启**:`lan enable` 注册开机自启——Windows 优先计划任务(默认登录自启,`--onstart` 开机即启需管理员),非管理员自动降级为**用户级 Startup 静默自启**(免管理员,启动脚本内联启动命令、被清理也会在开机时自动重建,v0.6.3 起不再弹 80070002);Linux 优先 **systemd 用户单元**(`systemctl --user`,登录自启;`--onstart` 附加 `loginctl enable-linger` 开机即启),systemd 不可用时自动降级**用户 crontab @reboot**(v0.6.4);`lan disable` 移除,`lan status` 查询。
137
- - **安全边界**:管理动作(init / config / token / lan / serve)不进 MCP,token 不远程暴露;远程智能体只能读写记忆,不能改配置、不能管 token。
139
+ - **安全边界**:管理动作(init / config / token / lan / serve)不进 MCP,token 不远程暴露;远程智能体只能读写记忆,且路径限记忆库内(export/import 的 out/src 必须落在库内)、distill 不支持 `--model`(仅本地 CLI),不能改配置、不能管 token。
138
140
  - 完整操作步骤见上文「局域网多机共享」章节与 [USER_GUIDE.md](USER_GUIDE.md)。
139
141
 
140
142
  ## 与其他方案对比
@@ -154,34 +156,40 @@
154
156
 
155
157
  ## 安装
156
158
 
157
- 三种方式任选其一,技能文件统一从 **npm** 获取(GitHub 无代理时较慢,npm 可配国内镜像加速)。
159
+ 元忆为「CLI + 技能」双体:`yotta-memory` 命令负责读写记忆库,技能负责教智能体工作流。以下四种方式任选,顺序即推荐优先级;技能文件一律从 **npm** 获取(GitHub 无代理较慢,npm 支持镜像)。
158
160
 
159
- ### 方式一:npx skills(推荐,生态标准入口)
160
- ```bash
161
- npx skills add YottaMeta/yotta-memory
161
+ ### 方式一:npm 一行装(推荐)
162
+
163
+ ```text
164
+ # 可选国内加速:npm config set registry https://registry.npmmirror.com
165
+ npx -y --package @yottameta/yotta-memory yotta-memory-install --agent <智能体名称> # 装到指定智能体默认用户级技能目录
166
+ npx -y --package @yottameta/yotta-memory yotta-memory-install --dir <智能体的技能目录> # 指到技能目录本身(如 ~/.codex/skills)
162
167
  ```
163
- > 自动把技能文件装到已检测到的智能体(Claude Code / Codex / Cursor / OpenCode 等 78+ 智能体)。此方式只装「技能指令」(SKILL.md 等);要使用 `yotta-memory` 读写命令,需另装 CLI:`npm install -g @yottameta/yotta-memory`(见方式二)。
164
168
 
165
- ### 方式二:npm 直接安装(CLI + 技能)
166
- ```bash
167
- # 国内加速(可选):npm config set registry https://registry.npmmirror.com
168
- npm install -g @yottameta/yotta-memory
169
- yotta-memory init # 初始化记忆库
170
- yotta-memory-install -g # 装进所有已识别智能体(用户级)
171
- yotta-memory-install --agent codex # 只装进指定智能体
169
+ - `--agent <name>` 自动装到该智能体默认用户级目录;`--list` 可查看各智能体默认目录。
170
+ - `--dir <路径>` 装到指定的技能目录;未收录的智能体用 `--dir` 指到它的技能目录。
171
+ - npmmirror 未同步新包(404):加 `--registry=https://registry.npmjs.org/`(国内需代理),或稍等镜像缓存。
172
+ - 若要读写记忆,需安装 CLI:`npm install -g @yottameta/yotta-memory`(用法见「CLI 用法」)。
173
+
174
+ ### 方式二:git clone(开发者 / 有 git 环境)
175
+
176
+ ```text
177
+ git clone https://github.com/YottaMeta/yotta-memory.git <智能体的技能目录>/yotta-memory
172
178
  ```
173
179
 
174
- > 全局安装后 `yotta-memory`(读写下)与 `yotta-memory-install`(安装器)两个命令均已加入 PATH。若不想全局安装,可一行运行安装器:`npx -y --package @yottameta/yotta-memory yotta-memory-install -g`。
180
+ ### 方式三:GitHub 下载压缩包(手动 / 无 git 环境)
175
181
 
176
- ### 方式三:install.sh / 手动复制
177
- 获取技能文件夹后(`npm pack` 解包或 `git clone`),进入技能文件夹:
178
- ```bash
179
- bash install.sh -g # 用户级;bash install.sh --list 查看全部目录
180
- bash install.sh --agent codex # 指定智能体
181
- bash install.sh --dir /path/to/skills
182
+ 在 GitHub 仓库 `YottaMeta/yotta-memory` 点 **Code → Download ZIP**,解压后把 `yotta-memory` 文件夹放进智能体技能目录。
183
+
184
+ ### 方式四:install.sh(多智能体一键脚本)
185
+
186
+ ```text
187
+ bash install.sh --agent <name> # 装到指定智能体默认用户级目录
188
+ bash install.sh --dir <path> # 装到指定目录
189
+ bash install.sh --list # 列出智能体 -> 默认目录
182
190
  ```
183
- 也可把整个 `yotta-memory` 文件夹复制到目标智能体的 skills 目录(常见位置见 install.sh --list)。
184
191
 
192
+ > 方式一走 npm 源(npmmirror / npmjs),不依赖 GitHub;方式二 / 三走 GitHub,国内无代理可能失败。
185
193
  ## 升级
186
194
 
187
195
  两种升级方式对应两种安装方式:
@@ -191,7 +199,7 @@ bash install.sh --dir /path/to/skills
191
199
  npm i -g @yottameta/yotta-memory
192
200
  ```
193
201
 
194
- **升级技能**:重新执行你当初的安装命令即可(`npx skills add YottaMeta/yotta-memory` 或 `yotta-memory-install -g`),覆盖旧版本技能文件夹。
202
+ **升级技能**:重跑「安装」节中的命令(如 `npx -y --package @yottameta/yotta-memory yotta-memory-install --agent <name>` 或 `bash install.sh --agent <name>`),覆盖旧版技能文件夹。
195
203
 
196
204
  > 升级只影响命令与技能文件,**不会动你已存的记忆**(记忆是独立于安装的文件,保留在原目录)。
197
205
 
@@ -282,7 +290,7 @@ yotta-memory recall --type FACT --limit 10
282
290
  }
283
291
  ```
284
292
 
285
- 连接后可通过 MCP tools(remember / recall / search / forget / archive / reindex / export / import / agent_info)读写记忆与确认身份;管理动作(init / config / token / lan / serve)不进 MCP,token 管理不远程暴露。`X-Agent-Id` 必须与 token 登记的智能体一致;读取分区规则与 CLI 相同(FACT 公共可读,PREF / BOUND / COMMIT 私密隔离)。
293
+ 连接后可通过 MCP tools(remember / recall / search / forget / archive / reindex / export / import / agent_info)读写记忆与确认身份;管理动作(init / config / token / lan / serve)不进 MCP,token 管理不远程暴露;MCP export/import 路径限记忆库内、distill 不支持 `--model`(仅本地 CLI)。`X-Agent-Id` 必须与 token 登记的智能体一致;读取分区规则与 CLI 相同(FACT 公共可读,PREF / BOUND / COMMIT 私密隔离)。
286
294
 
287
295
  ### 位置持久化
288
296
 
package/SKILL.md CHANGED
@@ -1,14 +1,14 @@
1
1
  ---
2
2
  name: yotta-memory
3
3
  description: "元忆 —— 有权限边界的文件式智能体记忆。文件式、零依赖、可 diff/回滚:让任何 AI 智能体活过会话,开工 recall 恢复上下文、重要信息 remember 落盘、收工归档。类型体系 FACT(公共共享)/ PREF / BOUND / COMMIT(私密隔离)。触发:记住、别忘了、记一笔、记忆、remember、recall、跨会话、上次说到、续测、交接、归档、记忆盘、共享记忆、局域网记忆、画像、开工上下文、记忆守则、profile、context、越用越懂、语义检索、反馈、维护、蒸馏、feedback、maintain、distill、explain、自我学习、自我进化、自我提升、查看平台分页、recall 候选预过滤"
4
- version: 0.8.3
4
+ version: 0.8.5
5
5
  license: MIT
6
6
  ---
7
7
 
8
8
  # yotta-memory(元忆)— 有权限边界的文件式智能体记忆
9
9
 
10
10
  > 一句话:元忆 —— 有权限边界的文件式智能体记忆(不注入、可 diff、能回滚;FACT 共享、PREF / BOUND / COMMIT 私密隔离)。
11
- > 版本:0.8.2 | 最后更新:2026-08-27
11
+ > 版本:0.8.5 | 最后更新:2026-08-29
12
12
 
13
13
  ## 这是什么
14
14
 
@@ -113,7 +113,7 @@ license: MIT
113
113
  - 未装 → 🔒 **征得同意后**自动安装(三选一,AI 判断;装后回读 `--version` 出版本即就绪):
114
114
  - 临时使用:`npx -y @yottameta/yotta-memory`
115
115
  - 长期使用:`npm i -g @yottameta/yotta-memory`
116
- - 离线 / 国内 / 无 npm:git clone 仓库(或手动下载 install.sh)后执行 `bash install.sh -g`
116
+ - 离线 / 国内 / 无 npm:git clone 仓库(或手动下载 install.sh)后执行 `bash install.sh --agent <name>`
117
117
 
118
118
  **A. 确认记忆库位置**(AI 不会自动知道记忆库在哪,先检测,避免「recall 读空库 / 错库」):
119
119
 
@@ -291,7 +291,7 @@ license: MIT
291
291
  4. 按当前智能体机制重载 MCP(必要时请用户重启会话);
292
292
  5. 用 MCP tools 读写记忆。
293
293
 
294
- > MCP 工具集与 CLI 一致:remember / recall / search / forget / archive / reindex / export / import / profile;管理动作(init / config / token / lan / serve)不进 MCP,token 管理不远程暴露。
294
+ > MCP 工具集与 CLI 一致:remember / recall / search / forget / archive / reindex / export / import / profile;管理动作(init / config / token / lan / serve)不进 MCP,token 管理不远程暴露;MCP export/import 路径限记忆库内、distill 不支持 `--model`(仅本地 CLI)。
295
295
 
296
296
  ### 4.7 MCP 配置位置表
297
297
  | 智能体 | 常见 MCP 配置位置 |
package/USER_GUIDE.md CHANGED
@@ -42,7 +42,7 @@
42
42
  |---|---|---|
43
43
  | npm 全局(推荐) | `npm i -g @yottameta/yotta-memory` | 长期使用 |
44
44
  | npx 临时 | `npx -y @yottameta/yotta-memory` | 临时试用 |
45
- | install.sh | git clone 仓库后 `bash install.sh -g`(或手动下载 install.sh 执行)| 离线 / 国内 / 无 npm |
45
+ | install.sh | git clone 仓库后 `bash install.sh --agent <name>`(或手动下载 install.sh 执行)| 离线 / 国内 / 无 npm |
46
46
 
47
47
  安装后验证:`yotta-memory --version` 能输出版本号即成功。
48
48
 
@@ -50,8 +50,8 @@
50
50
 
51
51
  | 方式 | 命令 | 适用 |
52
52
  |---|---|---|
53
- | npx skills(生态标准入口) | `npx skills add YottaMeta/yotta-memory` | 自动检测已装智能体 |
54
- | 安装器(npm 全局时) | `yotta-memory-install -g` / `yotta-memory-install --agent codex` | 装进所有 / 指定智能体 |
53
+ | npx 一行装(推荐) | `npx -y --package @yottameta/yotta-memory yotta-memory-install --agent <name>` | 装到指定智能体默认用户级目录 |
54
+ | 安装器(npm 全局时) | `yotta-memory-install --agent <name>` | 装到指定智能体目录 |
55
55
  | 手动 | 把整个 `yotta-memory` 文件夹复制到智能体的 skills 目录 | 离线 |
56
56
 
57
57
  > CLI 与技能分工不同:CLI 让命令行能读写记忆;技能让 AI 知道「开工 recall 恢复上下文、重要信息 remember 落盘、收工归档」。只装 CLI 不装技能,AI 不会自动使用这套工作流。
@@ -356,7 +356,7 @@ yotta-memory remember FACT 主题 内容 # 智能体落盘
356
356
  - token 等同密码:只给需要接入的智能体,别外传。
357
357
  - 私密区机制级加密(v0.7 起):PREF / BOUND / COMMIT 私密记忆默认落盘为密文(AES-256-GCM 信封加密),任何没有对应 owner 密钥的 AI 即使读到密文文件也解不开;隔离 = 权限边界(scope/owner)+ 机制层机密保护。用户是数据所有者,经 `yotta-memory view` 口令解锁可看全部。
358
358
  - 记忆读写一律走 CLI / MCP;禁止用 shell(`Get-ChildItem` / `cat` / `ls` / `type` 等)直接读改记忆库目录下的文件——否则会绕过 scope/owner 权限边界。
359
- - 管理动作(init / config / token / lan / serve)不通过 MCP 暴露,远程只能读写记忆,不能改配置、不能管 token。
359
+ - 管理动作(init / config / token / lan / serve)不通过 MCP 暴露,远程只能读写记忆(路径限记忆库内,export/import 的 out/src 必须落在库内;distill 不支持 `--model`,仅本地 CLI),不能改配置、不能管 token。
360
360
  - `--no-auth` 会关闭鉴权,仅限可信内网使用。
361
361
  - 数据主权在用户:公共 FACT 明文、随时可看可改可删;私密区加密,用户经 `yotta-memory view` 口令解锁后同样可看、可改、可删、可导出。
362
362
  - 「记忆守则」内置底线:陪伴不操控 / 理解不越界(不贴标签)/ 诚实不伪装 / 不降格;数据安全(被遗忘权 = `forget`);宿主隔离(只写本记忆库,不读写宿主 AI 自身 memory / 配置 / 系统文件)。
@@ -22,7 +22,7 @@ const crypto = require('crypto');
22
22
  const http = require('http');
23
23
  const child_process = require('child_process');
24
24
 
25
- const VERSION = '0.8.3';
25
+ const VERSION = '0.8.5';
26
26
  const TYPES = ['FACT', 'PREF', 'BOUND', 'COMMIT'];
27
27
  const TYPE_DIRS = { FACT: 'facts', PREF: 'prefs', BOUND: 'bounds', COMMIT: 'commits' };
28
28
  const PUBLIC_DIR = 'facts';
@@ -100,6 +100,56 @@ function typeSubdir(type, owner) {
100
100
  function defaultScope(type) {
101
101
  return PRIVATE_TYPES.indexOf(String(type).toUpperCase()) === -1 ? 'public' : 'private';
102
102
  }
103
+ // ---- 安全边界:路径必须落在记忆库根内(防 MCP 任意路径读写,v0.8.5)----
104
+ function resolveWithinRoot(root, p) {
105
+ let abs = path.isAbsolute(p) ? path.resolve(p) : path.resolve(root, p);
106
+ const r = path.resolve(root);
107
+ if (abs === r) return abs;
108
+ if (abs.startsWith(r + path.sep)) return abs;
109
+ return null;
110
+ }
111
+ function isWithinRoot(root, p) { return !!resolveWithinRoot(root, p); }
112
+ // 把命令行安全拆分为 argv(支持 ' " 引号包参,但绝不经过 shell,防元字符注入)
113
+ function splitCommandArgv(s) {
114
+ const argv = [];
115
+ let cur = '';
116
+ let quote = null;
117
+ for (let i = 0; i < String(s).length; i++) {
118
+ const c = String(s)[i];
119
+ if (quote) {
120
+ if (c === quote) { quote = null; continue; }
121
+ if (c === '\\' && quote === '"') { cur += String(s)[i + 1] || ''; i++; continue; }
122
+ cur += c; continue;
123
+ }
124
+ if (c === '"' || c === "'") { quote = c; continue; }
125
+ if (c === ' ' || c === '\t') { if (cur) { argv.push(cur); cur = ''; } continue; }
126
+ cur += c;
127
+ }
128
+ if (cur) argv.push(cur);
129
+ return argv;
130
+ }
131
+ // 模型命令允许清单:环境变量 YOTTA_DISTILL_MODELS(逗号分隔可执行名,不含扩展名)或 config.distill_models;
132
+ // 未配置时放行(本地宿主 CLI 自担风险,但已去除 shell 注入面);MCP 已在上层直接拒绝 model,不达此处。
133
+ function distillModelAllowlist() {
134
+ const env = (process.env.YOTTA_DISTILL_MODELS || '').split(',').map(function (x) { return x.trim().toLowerCase(); }).filter(Boolean);
135
+ if (env.length) return env;
136
+ const cfg = loadConfig();
137
+ const c = cfg && (cfg.distill_models || []);
138
+ if (Array.isArray(c) && c.length) return c.map(function (x) { return String(x).trim().toLowerCase(); }).filter(Boolean);
139
+ return null;
140
+ }
141
+ // 安全执行外部模型命令:仅允许清单内可执行名;argv 分离、不经 shell。
142
+ function runDistillModel(modelStr, payload) {
143
+ const argv = splitCommandArgv(modelStr);
144
+ if (!argv.length) throw new Error('模型命令为空');
145
+ const base = path.basename(argv[0]).toLowerCase().replace(/\.exe$/i, '');
146
+ const allow = distillModelAllowlist();
147
+ if (allow && allow.length && allow.indexOf(base) === -1) {
148
+ throw new Error('模型命令不在允许清单内: ' + base + '(可用: ' + allow.join(', ') + ';或设环境变量 YOTTA_DISTILL_MODELS)');
149
+ }
150
+ const r = child_process.spawnSync(argv[0], argv.slice(1), { input: payload, encoding: 'utf8', maxBuffer: 1024 * 1024, shell: false, windowsHide: true });
151
+ return r;
152
+ }
103
153
  function parseFrontmatter(text) {
104
154
  const m = text.match(/^---\s*\n([\s\S]*?)\n---/);
105
155
  if (!m) return { meta: {}, body: text };
@@ -1626,7 +1676,7 @@ function distillCore(opts) {
1626
1676
  if (opts.model) {
1627
1677
  try {
1628
1678
  const payload = JSON.stringify({ summary: lines.join('\n'), entries: entries.map(function (e) { return { type: e.type, subject: e.subject, statement: e.statement, tags: e.tags, confidence: e.confidence, access_count: e.access_count, feedback_net: e.feedback_net }; }).slice(0, 200) });
1629
- const r = child_process.spawnSync(String(opts.model), { input: payload, encoding: 'utf8', maxBuffer: 1024 * 1024, shell: process.platform === 'win32' });
1679
+ const r = runDistillModel(String(opts.model), payload);
1630
1680
  if (r.stdout) modelOut = String(r.stdout).trim();
1631
1681
  if (!modelOut) modelOut = '(模型无输出)';
1632
1682
  body += '\n## 四、模型提炼(--model ' + opts.model + ')\n\n' + modelOut + '\n';
@@ -2603,13 +2653,13 @@ function mcpTools() {
2603
2653
  { name: 'forget', description: '删除一条记忆。file 为记忆文件路径(如 facts/2026-08-24-0001.md 或文件名)', inputSchema: { type: 'object', properties: { file: { type: 'string' } }, required: ['file'] } },
2604
2654
  { name: 'archive', description: '归档旧记忆。days 默认 180;threshold 默认 0.4', inputSchema: { type: 'object', properties: { days: { type: 'number' }, threshold: { type: 'number' } } } },
2605
2655
  { name: 'reindex', description: '重建索引(手动改 .md 后校正;扫描 facts/prefs/bounds/commits 四目录)', inputSchema: { type: 'object', properties: {} } },
2606
- { name: 'export', description: '导出全部记忆到引擎主机上的 JSON 文件。out 可选(默认 <记忆库>/yottamemory-export-<日期>.json)', inputSchema: { type: 'object', properties: { out: { type: 'string' } } } },
2607
- { name: 'import', description: '从引擎主机上的 JSON 文件导入记忆。src 为文件路径(可绝对路径,或相对记忆库目录)', inputSchema: { type: 'object', properties: { src: { type: 'string' } }, required: ['src'] } },
2656
+ { name: 'export', description: '导出全部记忆到记忆库内的 JSON 文件。out 可选(默认 <记忆库>/yottamemory-export-<日期>.json;仅限记忆库内路径)', inputSchema: { type: 'object', properties: { out: { type: 'string' } } } },
2657
+ { name: 'import', description: '从记忆库内的 JSON 文件导入记忆。src 为文件路径(相对记忆库目录,或记忆库内绝对路径;仅限记忆库内)', inputSchema: { type: 'object', properties: { src: { type: 'string' } }, required: ['src'] } },
2608
2658
  { name: 'agent_info', description: '查看当前智能体身份与登记状态(远端读经 token 校验的 X-Agent-Id;本机读 YOTTA_AGENT_ID)。开工先确认「我是谁」,禁止从记忆里抄别人的 ID', inputSchema: { type: 'object', properties: {} } },
2609
2659
  { name: 'profile', description: '生成当前智能体的用户画像(只读聚合 private/<owner>/ 下 PREF/BOUND/COMMIT 原文,零推断,写入 private/<owner>/profile.md)。owner 默认当前智能体', inputSchema: { type: 'object', properties: { owner: { type: 'string' } } } },
2610
2660
  { name: 'feedback', description: '显式使用反馈(自我学习):useful/useless 调整记忆 weight/confidence/feedback_net。file 为记忆文件路径或文件名', inputSchema: { type: 'object', properties: { file: { type: 'string' }, useful: { type: 'boolean' }, useless: { type: 'boolean' }, reason: { type: 'string' } }, required: ['file'] } },
2611
2661
  { name: 'maintain', description: '记忆自组织(自我进化):规则层归档/遗忘/去重预览。默认 dry-run;apply 才执行,purge 才真删', inputSchema: { type: 'object', properties: { apply: { type: 'boolean' }, purge: { type: 'boolean' }, dedup: { type: 'boolean' }, threshold: { type: 'number' }, age: { type: 'number' } } } },
2612
- { name: 'distill', description: '心理日志蒸馏(自我提升):统计摘要/主题画像/知识地图。owner 默认当前智能体', inputSchema: { type: 'object', properties: { owner: { type: 'string' }, subject: { type: 'string' }, model: { type: 'string' } } } },
2662
+ { name: 'distill', description: '心理日志蒸馏(自我提升):统计摘要/主题画像/知识地图。owner 默认当前智能体(MCP 不支持 --model 外部命令)', inputSchema: { type: 'object', properties: { owner: { type: 'string' }, subject: { type: 'string' } } } },
2613
2663
  { name: 'explain', description: '解释单条记忆效用分项(为什么靠前/归档/遗忘)。file 为记忆文件路径或文件名', inputSchema: { type: 'object', properties: { file: { type: 'string' } }, required: ['file'] } },
2614
2664
  ];
2615
2665
  }
@@ -2641,11 +2691,22 @@ function callTool(name, args, ctx) {
2641
2691
  return { text: '已重建索引 ' + root + '(' + cnt + ' 条)', error: false };
2642
2692
  }
2643
2693
  if (name === 'export') {
2644
- const r = exportCore(userRoot(), args.out ? String(args.out) : null);
2694
+ const root = userRoot();
2695
+ let out = null;
2696
+ if (args.out) {
2697
+ const safe = resolveWithinRoot(root, String(args.out));
2698
+ if (!safe) return { text: '拒绝: MCP 导出路径必须位于记忆库内(' + root + '),已阻止任意路径写入。', error: true };
2699
+ out = safe;
2700
+ }
2701
+ const r = exportCore(root, out);
2645
2702
  return { text: r.text, error: r.error };
2646
2703
  }
2647
2704
  if (name === 'import') {
2648
- const r = importCore(userRoot(), String(args.src || ''));
2705
+ const root = userRoot();
2706
+ const src = String(args.src || '');
2707
+ const safe = resolveWithinRoot(root, src);
2708
+ if (!safe) return { text: '拒绝: MCP 导入路径必须位于记忆库内(' + root + '),已阻止任意路径读取。', error: true };
2709
+ const r = importCore(root, safe);
2649
2710
  return { text: r.text, error: r.error };
2650
2711
  }
2651
2712
  if (name === 'agent_info') {
@@ -2681,7 +2742,8 @@ function callTool(name, args, ctx) {
2681
2742
  return { text: r.text, error: r.error };
2682
2743
  }
2683
2744
  if (name === 'distill') {
2684
- const r = distillCore({ selfAgent: agent, owner: args.owner ? String(args.owner) : agent, subject: args.subject ? String(args.subject) : '', model: args.model ? String(args.model) : '' });
2745
+ if (args.model) return { text: '拒绝: MCP 不支持 --model(任意命令执行风险);请在引擎主机本地 CLI 执行 yotta-memory distill --model <命令>。', error: true };
2746
+ const r = distillCore({ selfAgent: agent, owner: args.owner ? String(args.owner) : agent, subject: args.subject ? String(args.subject) : '', model: '' });
2685
2747
  return { text: r.text, error: r.error };
2686
2748
  }
2687
2749
  if (name === 'explain') {
@@ -3328,6 +3390,10 @@ async function main() {
3328
3390
  else if (a === '--password') opts.password = v;
3329
3391
  else if (a === '--new-password') opts.newPassword = v;
3330
3392
  else if (a === '--recovery-key') opts.recoveryKey = v;
3393
+ else if (a === '--reason') opts.reason = v;
3394
+ else if (a === '--merge') opts.merge = v;
3395
+ else if (a === '--model') opts.model = v;
3396
+ else if (a === '--subject') opts.subject = v;
3331
3397
  } else if (a.startsWith('--')) {
3332
3398
  console.error('未知选项: ' + a);
3333
3399
  process.exit(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yottameta/yotta-memory",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Yuanyi (元忆) — boundary-aware, file-based memory for AI agents. File-based, zero-dependency, diff/rollback-able; FACT/PREF/BOUND/COMMIT four types (public shared / private isolated), user-level + project-level storage; v0.8 semantic search + usage feedback loop + rule-layer self-organization + psychological-log distillation (self-learning/self-evolving/self-improving).",
5
5
  "license": "MIT",
6
6
  "keywords": [