@yottameta/yotta-memory 0.16.4 → 0.16.6
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 +21 -0
- package/README.md +1 -0
- package/README.zh-CN.md +1 -0
- package/SKILL.md +16 -3
- package/USER_GUIDE.md +1 -1
- package/bin/plugin-mcp.js +111 -0
- package/bin/yotta-memory.js +40 -6
- package/package.json +1 -1
- package/references/protocol.md +1 -0
- package/skill-manifest.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## v0.16.6 (2026-09-23)
|
|
2
|
+
|
|
3
|
+
**插件 MCP 身份启动器(Agent Plugin 开箱可用)**
|
|
4
|
+
|
|
5
|
+
- 新增 `bin/plugin-mcp.js`:宿主只替换 `${PLUGIN_ROOT}`、不替换 `${AGENT_ID}` / `${AGENT_KEY_FILE}` 时,按「宿主替换值 → 环境变量 → `PLUGIN_DATA/identity.json` → 未授权可执行指引」解析身份。
|
|
6
|
+
- 未装配身份时不再把字面量占位符传给引擎:以未授权模式启动(公共 FACT 可读、私密 fail-closed),并输出含 `key claim` 与 `identity.json` 的可执行指引。
|
|
7
|
+
- `key claim <id> --plugin-data <PLUGIN_DATA>`:一条命令同时写入插件 key 与 `identity.json`;与 `--to` / `--agent-key-file` 互斥校验。
|
|
8
|
+
- 插件 `mcp.json` 入口由 `yotta-memory.js` 改为 `plugin-mcp.js`;宿主替换占位符的旧路径继续有效。
|
|
9
|
+
- 回归:`test/plugin-mcp-launcher.test.js`(身份优先级 / 无身份指引)+ `test/plugin-claim-binding.test.js`(claim → 插件身份 → 私密读取端到端);全量 `npm test` 167/167 PASS。
|
|
10
|
+
- 版本对齐:package.json / SKILL.md frontmatter / skill-manifest.json / CHANGELOG / 引擎 VERSION = 0.16.6。
|
|
11
|
+
|
|
12
|
+
## v0.16.5 (2026-09-22)
|
|
13
|
+
|
|
14
|
+
**doctor --json 稳定契约补齐**
|
|
15
|
+
|
|
16
|
+
- `doctor --json` 顶层新增 `schemaVersion: 1`、`encryption: boolean`、`migration_required: [{ agent, reason }]`。
|
|
17
|
+
- 保留 `checks`、`warnings`、`identity`、`text` 等既有字段;旧消费方无需改动。
|
|
18
|
+
- `migrationRequiredInfo()` 同步返回逐 owner 的 `entries`,供 CLI JSON 与宿主契约共用。
|
|
19
|
+
- 回归覆盖明文库空迁移数组、加密库未绑定 owner 迁移条目及 warning 兼容。
|
|
20
|
+
- 版本对齐:package.json / SKILL.md frontmatter / skill-manifest.json / CHANGELOG / 引擎 VERSION = 0.16.5。
|
|
21
|
+
|
|
1
22
|
## v0.16.4 (2026-09-22)
|
|
2
23
|
|
|
3
24
|
**agent-key 缺文件提示范围修复**
|
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
> 📖 The user-facing operations manual lives in [USER_GUIDE.md](USER_GUIDE.md).
|
|
25
25
|
|
|
26
|
+
> 🆕 **v0.16.5 (doctor JSON contract)**: `doctor --json` now exposes stable top-level `schemaVersion`, `encryption`, and `migration_required` fields while preserving the existing `checks` / `warnings` / `identity` structure.
|
|
26
27
|
> 🆕 **v0.16.4 (agent-key prompt scope)**: a missing `--agent-key-file` no longer prints a global `stderr` warning for public or maintenance commands. Only real private-data access fails closed, with the missing path, `view` / `key bind`, and `key status` / `key claim` guidance. `whoami --json`, `doctor --json`, and `config get --json` expose structured `identity.mode` / `identity.agentKeyStatus` fields.
|
|
27
28
|
> 🆕 **v0.16.2 (first-boot fixes)**: an empty encrypted store can unlock `view` with the recovery key; non-TTY hosts can use `--password-stdin`; recovery keys can be written with `--recovery-key-out <file>`; a missing `--agent-key-file` degrades to unauthenticated public-only mode; an empty plaintext store can be migrated to encryption; `view` reports port reuse/conflicts clearly.
|
|
28
29
|
> 🆕 **v0.16.3 (migration quick path)**: convert a plaintext store to encryption with
|
package/README.zh-CN.md
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
> 📖 面向用户的操作手册见 [USER_GUIDE.md](USER_GUIDE.md)。
|
|
25
25
|
|
|
26
|
+
> 🆕 **v0.16.5(doctor JSON 契约)**:`doctor --json` 顶层新增稳定字段 `schemaVersion` / `encryption` / `migration_required`,同时保留原有 `checks` / `warnings` / `identity` 结构。
|
|
26
27
|
> 🆕 **v0.16.4(agent-key 提示范围)**:`--agent-key-file` 不存在时不再为公共 / 维护命令输出全局 `stderr` 警告;只有真正访问私密区才 fail-closed,并给出缺失路径、`view` / `key bind`、`key status` / `key claim` 步骤。`whoami --json`、`doctor --json`、`config get --json` 返回结构化 `identity.mode` / `identity.agentKeyStatus`。
|
|
27
28
|
> 🆕 **v0.16.2(首启修复)**:空加密库 `view` 可用恢复钥匙解锁;非 TTY 支持 `--password-stdin`;恢复钥匙支持 `--recovery-key-out <文件>`;`--agent-key-file` 不存在时降级未授权(公共 FACT 可读、私密 fail-closed);空明文库可直接 `migrate` 启用加密;`view` 端口占用给明确提示。
|
|
28
29
|
> 🆕 **v0.16.3(迁移最短路径)**:明文库第一次转加密:
|
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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 候选预过滤、任务相关记忆、--focus、--embedding、压缩遗忘、consolidate、周期摘要、自动合并、分类型衰减、回滚、备份、backup、防误删、doctor、事务快照
|
|
4
|
-
version: 0.16.
|
|
4
|
+
version: 0.16.6
|
|
5
5
|
license: MIT
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -19,6 +19,7 @@ license: MIT
|
|
|
19
19
|
- **MCP 工具分组(v0.15.0)**:`serve --tools core|full` 控制工具暴露面。`core` 固定为 `context / recall / search / remember`,适合常驻;`full` 为现有 16 工具,适合维护与诊断。未指定时默认 `full`,保持现有配置兼容。
|
|
20
20
|
- **身份模型(v0.16.0)**:身份不再从环境变量读取。HTTP / 远程 MCP 只认请求头 `Authorization` + `X-Agent-Id` + `X-Agent-Key`;stdio MCP 只认显式参数 `--agent-id` + `--agent-key-file`;CLI 用 `--agent` + `--agent-key` / `--agent-key-file`。旧身份 env 会在 MCP 启动时被明确拒绝。
|
|
21
21
|
- **未授权提示边界(v0.16.4)**:`--agent-key-file` 不存在时不再由主入口向全局 `stderr` 告警。公共 / 维护命令保持安静;只有真正访问私密区时才 fail-closed,并给出缺失文件、`view` / `key bind`、`key status` / `key claim` 的可操作步骤。`whoami --json`、`doctor --json`、`config get --json` 返回 `identity.mode` / `identity.agentKeyStatus`。
|
|
22
|
+
- **doctor JSON 稳定契约(v0.16.5)**:`doctor --json` 顶层新增 `schemaVersion`(当前 `1`)、`encryption`(布尔)、`migration_required`(`[{agent, reason}]`)。原有 `checks` / `warnings` / `identity` / `text` 字段保持兼容。
|
|
22
23
|
- **运行时稳定入口(v0.16.0 M2)**:`runtime install --from-current` 把当前引擎安装到 `<runtimeRoot>/versions/<version>/` 并创建 `<runtimeRoot>/current` 稳定指针;`runtime use <version>` 原子切换、`runtime rollback` 回滚、`runtime status` 查看漂移。stdio MCP、`lan enable` 与备份调度只指向 `<runtimeRoot>/current/bin/yotta-memory.js`,不写版本目录。
|
|
23
24
|
- **运行时诊断与握手(v0.16.0 M3)**:`doctor --runtime` 检查 CLI / current / runtime.json / MCP 配置 / 运行中 server / 技能副本 / 身份模式漂移,逐项给出实际版本、期望版本、修复命令和是否阻断;MCP `initialize` / `server/discover` 的 `serverInfo` 返回 `runtimePath` / `identityMode` / `toolProfile`。
|
|
24
25
|
- **自我学习 / 自我进化 / 自我提升(v0.8.0)**:`recall` 语义检索(同义词 / 拼音 / 字段加权 / 模糊匹配,零依赖);`feedback` 显式使用反馈闭环(useful / useless → weight / confidence / feedback_net 演化,越用越懂);`maintain` 规则层自组织(统一效用分 + 年龄自动归档 / 遗忘候选 / 去重,默认 dry-run,immutable / BOUND 豁免);`distill` 心理日志蒸馏(统计摘要 / 主题画像 / 知识地图,可选 `--model` 外部模型增强);`explain` 查看单条记忆效用分项。
|
|
@@ -142,6 +143,16 @@ yotta-memory doctor --json
|
|
|
142
143
|
- 不提供 CLI 跳过快照的开关;`--allow-same-volume` 只用于 `backup create` 的显式临时备份,不会绕过破坏性写入门。
|
|
143
144
|
- `context` 会展示 doctor 的 warning / critical;critical 时明确提示“破坏性写入已锁定”。
|
|
144
145
|
- `forget` 仍只移入 `.trash/`,不重复创建整库快照。
|
|
146
|
+
- `doctor --json` 稳定字段(v0.16.5):
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"schemaVersion": 1,
|
|
151
|
+
"encryption": false,
|
|
152
|
+
"migration_required": [],
|
|
153
|
+
"identity": { "mode": "authenticated", "agentKeyStatus": "present" }
|
|
154
|
+
}
|
|
155
|
+
```
|
|
145
156
|
|
|
146
157
|
|
|
147
158
|
## 记忆守则(Memory Doctrine,v0.6.0)
|
|
@@ -232,7 +243,9 @@ yotta-memory doctor --json
|
|
|
232
243
|
- 输出 `memory_home: (未设置,默认 ~/.yottamemory)` → 🔒 征得同意后引导设置:问用户用默认还是指定目录(项目级 `<repo>/.yottamemory`、记忆盘等),确认后 AI 执行 `yotta-memory config set memory_home <目录>`,回读 `config get` 验证。
|
|
233
244
|
2. **已有记忆**:目标目录已存在 `facts/` 等子目录或 `index.json` → 直接 recall;全新目录 → 按「便携记忆盘模式 §0.3」初始化。
|
|
234
245
|
3. **私密区为明文(无 `keys/`;`doctor` 显示「加密: 否」)**:首次使用即主动告知风险——明文私密记忆(PREF / BOUND / COMMIT)可被同机任何能读文件的进程或用户直接看到;然后给出《明文库转加密(第一次最短路径)》。口令与迁移必须由用户本人执行,AI 只讲解并负责后续 `key claim`。用户明确拒绝加密时,记录其选择并复述明文风险,不反复打扰。
|
|
235
|
-
4.
|
|
246
|
+
4. **Agent Plugin 开箱装配(v0.16.6)**:插件 `mcp.json` 入口是 `bin/plugin-mcp.js`。宿主已替换身份占位符时优先用替换值;未替换时回退到 `YOTTA_MEMORY_AGENT_ID` + `YOTTA_MEMORY_AGENT_KEY_FILE`,再回退到 `PLUGIN_DATA/identity.json`。都没有时插件以未授权模式启动(公共 FACT 可读、私密 fail-closed)并打印绑定指引。绑定一条命令:用户在 `yotta-memory view` 授权后执行 `yotta-memory key claim <id> --plugin-data <PLUGIN_DATA>`(同时写 key 与 `identity.json`),重启会话即可。
|
|
247
|
+
|
|
248
|
+
5. **私密区已加密(存在 `keys/`)**:先 `yotta-memory key list` 确认本智能体是否有 agent binding;没有 → 告知用户由用户自己执行 `yotta-memory view` → 浏览器打开平台 → 输入主口令 → 点「授权」并保存只展示一次的 `agent_key`。用户授权后服务端会写 `keys/pending/<id>.key`;AI 在新会话执行 `yotta-memory key status <id>`(需要时显式加 `--to <AI_HOME>` 或 `--agent-key-file <文件>`;默认发现规则见下),有 pending 就执行 `yotta-memory key claim <id>`,落到 `<AI_HOME>/.yotta-memory-agent-key` 后再使用 `--agent-key-file`。**升级后首次调用元忆 / 重启会话时**,若输出 `[YTM_MIGRATION_REQUIRED]`,必须主动把 marker、受影响 agent 和处理步骤转达给用户。**AI 不得代替用户执行 `migrate` / `key bind` 迁移**,只负责提醒和讲解(marker 只列仍有私密数据、未绑定的 agent;仅有 legacy cache、无迁移数据的 owner 会单独提示,不进入迁移清单;公共 FACT 不受影响)。
|
|
236
249
|
|
|
237
250
|
**B. 确认本智能体唯一身份(强制,写私密记忆前必做)**:
|
|
238
251
|
|
|
@@ -278,7 +291,7 @@ yotta-memory doctor --json
|
|
|
278
291
|
| `yotta-memory forget <文件>` | 移入 `.trash/<时间>/` 回收区并写审计(v0.12.0;不再物理删除)|
|
|
279
292
|
| `yotta-memory backup volumes / setup --dir <目录> / status / ensure-daily / schedule enable|disable|status` | 每日自动备份(v0.12.0;只展示实际枚举的异卷、用户确认一次位置后默认每日执行,Windows Task Scheduler / systemd timer / launchd 调度,`serve` 补跑)|
|
|
280
293
|
| `yotta-memory backup create / list / doctor / restore <ID> --to <目录> / drill [<ID>]` | 备份、恢复与恢复演练(v0.12.0;独立盘校验、SHA-256 清单、排除 `keys/cache`、恢复默认只写新目录;drill 验证 manifest / 索引 / 测试私密解密)|
|
|
281
|
-
| `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>]` | 开工可靠性检查(v0.12.2;根目录 / 密钥库 / 索引 / 身份 / 最近备份;严重异常时锁定破坏性写入);全新空库的缺失 index / agents 降为 info;输出 agent home 发现规则与 `YOTTA_MEMORY_AGENT_HOME` 提示;加 `--runtime` 检查 CLI / current / MCP 配置 / 运行中 server / 技能副本漂移;v0.16.4 起 `--json` 含身份 / agent-key
|
|
294
|
+
| `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>]` | 开工可靠性检查(v0.12.2;根目录 / 密钥库 / 索引 / 身份 / 最近备份;严重异常时锁定破坏性写入);全新空库的缺失 index / agents 降为 info;输出 agent home 发现规则与 `YOTTA_MEMORY_AGENT_HOME` 提示;加 `--runtime` 检查 CLI / current / MCP 配置 / 运行中 server / 技能副本漂移;v0.16.4 起 `--json` 含身份 / agent-key 状态;v0.16.5 起顶层含 `schemaVersion` / `encryption` / `migration_required` |
|
|
282
295
|
| `yotta-memory archive [--days 180] [--threshold 0.35]` | 归档旧记忆(v0.8.0 统一效用分 + v0.10.0 分类型衰减;immutable / BOUND 豁免;私密归档入 `.archive/private/<owner>/<type>/`;阈值默认读 config `maintain_archived_utility`)|
|
|
283
296
|
| `yotta-memory reindex` | 重建索引(手动改 .md 后校正)|
|
|
284
297
|
| `yotta-memory export [--out f.json]` / `import <f.json>` | 导出 / 导入 |
|
package/USER_GUIDE.md
CHANGED
|
@@ -270,7 +270,7 @@ yotta-memory recall <关键词> --agent <id> --agent-key-file "<AI_HOME>/.yotta-
|
|
|
270
270
|
|
|
271
271
|
## 3.9 开工 doctor 与事务快照(v0.12.2)
|
|
272
272
|
|
|
273
|
-
- `yotta-memory doctor`:只读检查记忆库根目录、加密库密钥文件、公共索引、`agents.json` 与最近备份;加 `--json`
|
|
273
|
+
- `yotta-memory doctor`:只读检查记忆库根目录、加密库密钥文件、公共索引、`agents.json` 与最近备份;加 `--json` 可输出机器可读结果,顶层含 `schemaVersion` / `encryption` / `migration_required`,并保留 `identity.mode` / `identity.agentKeyStatus`。
|
|
274
274
|
- 严重异常(根目录缺失、密钥库缺文件、备份目录同卷)会返回非零退出码;此时 `context` 也会显示“破坏性写入已锁定”。
|
|
275
275
|
- `maintain --apply`、`consolidate --apply`、`merge`、`archive` 与 `--purge` 在写入前自动创建新的整库事务快照,并在 `.archive/audit-<日期>.jsonl` 记录 transaction / operation / snapshot。
|
|
276
276
|
- 未配置独立备份目录、doctor critical 或快照失败时,命令直接拒绝执行,原记忆保持不变;`forget` 仍只移入 `.trash/`,不重复创建整库快照。
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// yotta-memory(元忆)插件 MCP 启动器(v0.16.6)
|
|
3
|
+
// 宿主(Codex / Agent Plugins)只替换 ${PLUGIN_ROOT} 与注入 PLUGIN_ROOT / PLUGIN_DATA,
|
|
4
|
+
// 不替换 mcp.json 里的 ${AGENT_ID} / ${AGENT_KEY_FILE}。本启动器按优先级解析身份:
|
|
5
|
+
// 1) 宿主已替换的 --agent-id / --agent-key-file
|
|
6
|
+
// 2) YOTTA_MEMORY_AGENT_ID + YOTTA_MEMORY_AGENT_KEY_FILE 环境变量
|
|
7
|
+
// 3) PLUGIN_DATA/identity.json(agent_id / key_file;key_file 缺省 <PLUGIN_DATA>/.yotta-memory-agent-key)
|
|
8
|
+
// 4) 都没有 -> 以未授权模式启动,输出可执行的绑定指引(不出现字面量占位符)
|
|
9
|
+
// 绑定路径:用户在 yotta-memory view 授权后,AI 执行
|
|
10
|
+
// yotta-memory key claim <agent_id> --to <PLUGIN_DATA>
|
|
11
|
+
// 或写入 <PLUGIN_DATA>/identity.json。
|
|
12
|
+
'use strict';
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { spawn } = require('child_process');
|
|
16
|
+
|
|
17
|
+
const AGENT_KEY_FILENAME = '.yotta-memory-agent-key';
|
|
18
|
+
const PLACEHOLDER_RE = /^\$\{[A-Z_]+\}$/;
|
|
19
|
+
|
|
20
|
+
function cleanValue(value) {
|
|
21
|
+
const v = String(value == null ? '' : value).trim();
|
|
22
|
+
if (!v || PLACEHOLDER_RE.test(v)) return '';
|
|
23
|
+
return v;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readIdentityFile(pluginData) {
|
|
27
|
+
if (!pluginData) return null;
|
|
28
|
+
const file = path.join(pluginData, 'identity.json');
|
|
29
|
+
if (!fs.existsSync(file)) return null;
|
|
30
|
+
try {
|
|
31
|
+
const data = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
32
|
+
const id = cleanValue(data.agent_id || data.agentId || '');
|
|
33
|
+
if (!id) return null;
|
|
34
|
+
const keyFile = cleanValue(data.key_file || data.keyFile || '') ||
|
|
35
|
+
path.join(pluginData, AGENT_KEY_FILENAME);
|
|
36
|
+
return { id: id, keyFile: keyFile, source: 'plugin-data' };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolvePluginIdentity(opts, env) {
|
|
43
|
+
opts = opts || {};
|
|
44
|
+
env = env || process.env;
|
|
45
|
+
const hostId = cleanValue(opts.agentId);
|
|
46
|
+
const hostKey = cleanValue(opts.keyFile);
|
|
47
|
+
if (hostId && hostKey) {
|
|
48
|
+
return { id: hostId, keyFile: hostKey, source: 'host-args' };
|
|
49
|
+
}
|
|
50
|
+
const envId = cleanValue(env.YOTTA_MEMORY_AGENT_ID);
|
|
51
|
+
const envKey = cleanValue(env.YOTTA_MEMORY_AGENT_KEY_FILE);
|
|
52
|
+
if (envId && envKey) {
|
|
53
|
+
return { id: envId, keyFile: envKey, source: 'env' };
|
|
54
|
+
}
|
|
55
|
+
const fromData = readIdentityFile(cleanValue(env.PLUGIN_DATA));
|
|
56
|
+
if (fromData) return fromData;
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function parseArgs(argv) {
|
|
61
|
+
const rest = [];
|
|
62
|
+
const opts = { agentId: '', keyFile: '' };
|
|
63
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
64
|
+
const a = argv[i];
|
|
65
|
+
if (a === '--agent-id') { opts.agentId = argv[++i]; continue; }
|
|
66
|
+
if (a === '--agent-key-file') { opts.keyFile = argv[++i]; continue; }
|
|
67
|
+
rest.push(a);
|
|
68
|
+
}
|
|
69
|
+
return { rest: rest, opts: opts };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function guidanceText(pluginData) {
|
|
73
|
+
const dataDir = pluginData || '<PLUGIN_DATA>';
|
|
74
|
+
return [
|
|
75
|
+
'元忆插件 MCP 尚未装配智能体身份:宿主未替换 mcp.json 中的身份占位符,且未找到环境变量或 identity.json。',
|
|
76
|
+
'当前以未授权模式启动:公共 FACT 可读,私密记忆(PREF / BOUND / COMMIT)fail-closed。',
|
|
77
|
+
'绑定步骤(用户授权后由 AI 执行):',
|
|
78
|
+
' 1) 用户在 yotta-memory view 中授权本智能体;',
|
|
79
|
+
' 2) AI 执行 yotta-memory key claim <agent_id> --to ' + dataDir,
|
|
80
|
+
' 或写入 ' + path.join(dataDir, 'identity.json') + ':{"agent_id":"<agent_id>"}',
|
|
81
|
+
' 3) 重启会话后插件即可读取私密记忆。',
|
|
82
|
+
].join('\n');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function main() {
|
|
86
|
+
const parsed = parseArgs(process.argv.slice(2));
|
|
87
|
+
const ident = resolvePluginIdentity(parsed.opts, process.env);
|
|
88
|
+
const cli = path.join(__dirname, 'yotta-memory.js');
|
|
89
|
+
const args = [cli].concat(parsed.rest);
|
|
90
|
+
if (ident) {
|
|
91
|
+
args.push('--agent-id', ident.id, '--agent-key-file', ident.keyFile);
|
|
92
|
+
} else {
|
|
93
|
+
process.stderr.write(guidanceText(process.env.PLUGIN_DATA) + '\n');
|
|
94
|
+
}
|
|
95
|
+
const child = spawn(process.execPath, args, { stdio: 'inherit' });
|
|
96
|
+
child.on('exit', function (code, signal) {
|
|
97
|
+
if (signal) process.kill(process.pid, signal);
|
|
98
|
+
else process.exit(code == null ? 0 : code);
|
|
99
|
+
});
|
|
100
|
+
child.on('error', function (err) {
|
|
101
|
+
process.stderr.write('元忆插件 MCP 启动失败: ' + (err && err.message ? err.message : String(err)) + '\n');
|
|
102
|
+
process.exit(2);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
resolvePluginIdentity: resolvePluginIdentity,
|
|
108
|
+
guidanceText: guidanceText,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (require.main === module) main();
|
package/bin/yotta-memory.js
CHANGED
|
@@ -25,7 +25,7 @@ const net = require('net');
|
|
|
25
25
|
const child_process = require('child_process');
|
|
26
26
|
const { AsyncLocalStorage } = require('async_hooks');
|
|
27
27
|
|
|
28
|
-
const VERSION = '0.16.
|
|
28
|
+
const VERSION = '0.16.6';
|
|
29
29
|
// @generated view-html:start
|
|
30
30
|
const VIEW_HTML = "<!doctype html><html lang=\"zh\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>元忆 · 用户查看平台</title><style>\r\nbody{font-family:system-ui,-apple-system,\"Microsoft YaHei\",sans-serif;max-width:1000px;margin:24px auto;padding:0 16px;color:#1f2328;background:#fafafa}\r\nh1{font-size:22px} .card{background:#fff;border:1px solid #e2e2e2;border-radius:10px;padding:16px 18px;margin:14px 0;box-shadow:0 1px 2px rgba(0,0,0,.04)}\r\nbutton{background:#2563eb;color:#fff;border:0;border-radius:6px;padding:7px 14px;cursor:pointer;margin:2px;font-size:14px}\r\nbutton.danger{background:#dc2626} button.ghost{background:#e5e7eb;color:#1f2328}\r\ninput,select{padding:8px;border:1px solid #c9c9c9;border-radius:6px;margin:2px;font-size:14px;box-sizing:border-box}\r\ntable{border-collapse:collapse;width:100%;font-size:13px} td,th{border:1px solid #ececec;padding:6px 8px;text-align:left;vertical-align:top}\r\n.owner{display:inline-flex;align-items:center;gap:6px;border:1px solid #ddd;border-radius:8px;padding:5px 10px;margin:4px 6px 4px 0;background:#f6f8fa}\r\n.entry{border-bottom:1px solid #eee;padding:8px 0} .meta{color:#8a8a8a;font-size:12px}\r\n.err{color:#dc2626;margin-top:8px} .ok{color:#16a34a;margin-top:8px}\r\n#app{display:none} code{background:#f0f0f0;padding:1px 5px;border-radius:4px;font-size:12px}\r\n</style></head><body>\r\n<h1>元忆 · 用户查看平台 <span id=\"ver\" style=\"font-size:14px;color:#888\"></span></h1>\r\n<div id=\"lock\" class=\"card\">\r\n <p><b>输入主口令解锁</b>(口令只在本地内存派生,不落盘、不发送远端)。忘口令可在 CLI 用恢复钥匙重设:<code>yotta-memory reset-password --recovery-key <钥匙></code></p>\r\n <input type=\"password\" id=\"pw\" placeholder=\"主口令\" style=\"width:260px\">\r\n <button onclick=\"unlock()\">解锁</button>\r\n <div class=\"err\" id=\"lockerr\"></div>\r\n</div>\r\n<div id=\"app\">\r\n <div class=\"card\">\r\n <b>AI 列表</b>(✅=已授权可读自己私密,🔒=未授权)\r\n <div class=\"meta\" style=\"margin-top:6px\">「授权」由你(用户)操作:确认后生成只显示一次的 agent_key,请立即单独保存;服务端同时写临时待领取文件 <code>keys/pending/<agent_id>.key</code>,供该 AI 新会话领取,领取成功后自动删除。</div>\r\n <div id=\"owners\" style=\"margin-top:8px\"></div>\r\n </div>\r\n <div class=\"card\">\r\n <b>记忆</b>\r\n <input id=\"q\" placeholder=\"搜索关键词\" style=\"width:220px\" onkeydown=\"if(event.key==='Enter'){off=0;load()}\">\r\n <button onclick=\"off=0;load()\">搜索</button>\r\n <button class=\"ghost\" onclick=\"doExport()\">导出 JSON</button>\r\n <button class=\"ghost\" onclick=\"showRk()\">显示恢复钥匙</button>\r\n <span id=\"rkout\" style=\"font-size:12px;color:#888;margin-left:8px\"></span>\r\n <div id=\"meta\" style=\"margin-top:10px;font-size:12px;color:#666\"></div>\r\n <div id=\"entries\" style=\"margin-top:6px\"></div>\r\n <div id=\"pager\" style=\"margin-top:10px\">\r\n <button class=\"ghost\" id=\"prevb\" onclick=\"prevPage()\">上一页</button>\r\n <span id=\"pageinfo\" style=\"font-size:12px;color:#888;margin:0 8px\"></span>\r\n <button class=\"ghost\" id=\"nextb\" onclick=\"nextPage()\">下一页</button>\r\n </div>\r\n </div>\r\n <div class=\"card\">\r\n <b>重设口令</b><br>\r\n <input type=\"password\" id=\"cur\" placeholder=\"当前口令\">\r\n <input type=\"password\" id=\"np1\" placeholder=\"新口令\">\r\n <input type=\"password\" id=\"np2\" placeholder=\"确认新口令\">\r\n <button onclick=\"resetPw()\">重设</button>\r\n <span id=\"pwout\"></span>\r\n </div>\r\n</div>\r\n<script>\r\nfunction esc(s){return String(s==null?'':s).replace(/[&<>\"']/g,function(c){return{'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c];});}\r\nasync function api(p,b){try{const r=await fetch(p,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(b||{})});return await r.json();}catch(e){return{error:String(e)};}}\r\nasync function boot(){const s=await api('/api/status');document.getElementById('ver').textContent='v'+(s.version||'');if(s.unlocked){showApp();}}\r\nfunction showApp(){document.getElementById('lock').style.display='none';document.getElementById('app').style.display='block';loadOwners();load();}\r\nasync function unlock(){const d=await api('/api/unlock',{password:document.getElementById('pw').value});if(d.error){document.getElementById('lockerr').textContent=d.error;return;}showApp();}\r\nasync function loadOwners(){const d=await api('/api/owners');const box=document.getElementById('owners');box.innerHTML='';if(!d.owners||!d.owners.length){box.innerHTML=esc(d.hint||'(无 owner)');return;}\r\n for(const o of d.owners){const c=document.createElement('span');c.className='owner';c.innerHTML=esc(o.owner)+(o.authorized?' ✅':' 🔒')+' <button class=\"ghost\" data-a=\"'+esc(o.owner)+'\">授权</button><button class=\"danger\" data-r=\"'+esc(o.owner)+'\">吊销</button>';box.appendChild(c);}\r\n box.querySelectorAll('[data-a]').forEach(function(b){b.onclick=function(){var owner=b.getAttribute('data-a');if(!confirm('确认由你为用户授权 '+owner+' 读取其私密记忆?授权后将生成只显示一次的 agent_key,请立即保存;同时写入待领取文件供该 AI 新会话领取。AI 不应代为执行该授权操作。'))return;b.disabled=true;api('/api/authorize',{owner:owner}).then(function(d){b.disabled=false;if(!d||d.error){alert((d&&d.error)||'授权失败');loadOwners();return;}if(d.agentKey){showKey(d.agentKey);}loadOwners();});};});\r\n box.querySelectorAll('[data-r]').forEach(function(b){b.onclick=function(){if(!confirm('确认吊销 '+b.getAttribute('data-r')+' 的 agent_key?吊销后该智能体立即失去私密读写能力。'))return;api('/api/revoke',{owner:b.getAttribute('data-r')}).then(function(){loadOwners();});};});\r\nfunction showKey(k){var ov=document.createElement('div');ov.style.cssText='position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index:99';var box=document.createElement('div');box.className='card';box.style.cssText='max-width:640px;word-break:break-all';var t=document.createElement('div');t.innerHTML='<b>agent_key(只显示一次)</b>';var hint=document.createElement('div');hint.className='meta';hint.textContent='请用户立即单独保存。AI 新会话先执行 yotta-memory key status <agent_id>,有 pending 再执行 key claim <agent_id>;默认写入 AI_HOME/.yotta-memory-agent-key,需要时用 --to 或 --agent-key-file 指定。若 key 丢失,可吊销后重新授权;旧 key 会立即校验失败。';var ta=document.createElement('textarea');ta.readOnly=true;ta.value=k;ta.style.cssText='width:100%;height:72px;margin-top:8px;font-family:monospace;font-size:12px';var close=document.createElement('button');close.textContent='我已保存,关闭';close.onclick=function(){ov.remove();};box.appendChild(t);box.appendChild(hint);box.appendChild(ta);box.appendChild(close);ov.appendChild(box);document.body.appendChild(ov);ta.focus();ta.select();}\r\n}\r\nlet off=0,PS=50;\r\nasync function load(){const d=await api('/api/entries',{query:document.getElementById('q').value,offset:off,limit:PS});const meta=document.getElementById('meta');const pg=document.getElementById('pageinfo');if(meta)meta.textContent='共 '+d.count+' 条';const lim=d.limit||PS;const totalPg=Math.max(1,Math.ceil(d.count/lim));const curPg=Math.floor((d.offset||0)/lim)+1;if(pg)pg.textContent='第 '+curPg+' / '+totalPg+' 页';const box=document.getElementById('entries');box.innerHTML='';if(d.entries)for(const e of d.entries){const div=document.createElement('div');div.className='entry';div.innerHTML='<b>['+esc(e.type)+'] '+esc(e.subject)+'</b><div>'+esc(e.statement)+'</div><div class=\"meta\">'+esc(e.file)+' · owner='+esc(e.owner||'-')+' · '+esc(e.updated||e.created||'')+'</div>';box.appendChild(div);}const pb=document.getElementById('prevb'),nb=document.getElementById('nextb');if(pb)pb.disabled=(d.offset||0)<=0;if(nb)nb.disabled=!d.hasMore;}\r\nfunction prevPage(){if(off>=PS){off-=PS;load();}}\r\nfunction nextPage(){off+=PS;load();}\r\nasync function doExport(){const d=await api('/api/export');if(d.error){alert(d.error);return;}const blob=new Blob([JSON.stringify(d,null,2)],{type:'application/json'});const a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='yottamemory-view-export.json';a.click();}\r\nasync function showRk(){const d=await api('/api/recovery-key');document.getElementById('rkout').textContent=d.recoveryKey?('恢复钥匙: '+d.recoveryKey):(d.error||'');}\r\nasync function resetPw(){const np1=document.getElementById('np1').value,np2=document.getElementById('np2').value;if(np1!==np2){document.getElementById('pwout').innerHTML='<span class=\"err\">两次新口令不一致</span>';return;}\r\n const d=await api('/api/reset-password',{currentPassword:document.getElementById('cur').value,newPassword:np1});document.getElementById('pwout').innerHTML=d.error?('<span class=\"err\">'+esc(d.error)+'</span>'):('<span class=\"ok\">'+esc(d.text||'ok')+'</span>');}\r\nboot();\r\n</script></body></html>\r\n";
|
|
31
31
|
// @generated view-html:end
|
|
@@ -1142,9 +1142,16 @@ function resolveAgentKeyLocation(owner, opts) {
|
|
|
1142
1142
|
opts = opts || {};
|
|
1143
1143
|
const explicitHome = String(opts.to || '').trim();
|
|
1144
1144
|
const explicitFile = String(opts.agentKeyFile || '').trim();
|
|
1145
|
+
const explicitPluginData = String(opts.pluginData || '').trim();
|
|
1145
1146
|
if (explicitHome && explicitFile) {
|
|
1146
1147
|
return { ok: false, error: '--to 与 --agent-key-file 不能同时使用。' };
|
|
1147
1148
|
}
|
|
1149
|
+
if (explicitPluginData && (explicitHome || explicitFile)) {
|
|
1150
|
+
return { ok: false, error: '--plugin-data 不能与 --to / --agent-key-file 同时使用。' };
|
|
1151
|
+
}
|
|
1152
|
+
if (explicitPluginData) {
|
|
1153
|
+
return { ok: true, file: agentKeyFilePath(explicitPluginData), source: 'option:--plugin-data' };
|
|
1154
|
+
}
|
|
1148
1155
|
if (explicitFile) {
|
|
1149
1156
|
return { ok: true, file: path.resolve(explicitFile), source: 'option:--agent-key-file' };
|
|
1150
1157
|
}
|
|
@@ -1434,10 +1441,17 @@ function migrationRequiredInfo(root) {
|
|
|
1434
1441
|
const reasons = [];
|
|
1435
1442
|
if (actionable.some(function (owner) { return fs.existsSync(encCachePath(root, owner)); })) reasons.push('legacy_cache');
|
|
1436
1443
|
reasons.push('no_agent_binding');
|
|
1444
|
+
const entries = actionable.map(function (owner) {
|
|
1445
|
+
const ownerReasons = [];
|
|
1446
|
+
if (fs.existsSync(encCachePath(root, owner))) ownerReasons.push('legacy_cache');
|
|
1447
|
+
ownerReasons.push('no_agent_binding');
|
|
1448
|
+
return { agent: owner, reason: ownerReasons.join(',') };
|
|
1449
|
+
});
|
|
1437
1450
|
return {
|
|
1438
1451
|
marker: '[YTM_MIGRATION_REQUIRED] agent=' + actionable.join(',') + ' reason=' + reasons.join(','),
|
|
1439
1452
|
owners: actionable,
|
|
1440
1453
|
reasons: reasons,
|
|
1454
|
+
entries: entries,
|
|
1441
1455
|
legacyOnly: legacyOnly,
|
|
1442
1456
|
};
|
|
1443
1457
|
}
|
|
@@ -3109,8 +3123,11 @@ function doctorCore(opts) {
|
|
|
3109
3123
|
}
|
|
3110
3124
|
return {
|
|
3111
3125
|
error: false,
|
|
3126
|
+
schemaVersion: 1,
|
|
3112
3127
|
ok: critical.length === 0,
|
|
3113
3128
|
level: level,
|
|
3129
|
+
encryption: encrypted,
|
|
3130
|
+
migration_required: migration ? migration.entries : [],
|
|
3114
3131
|
critical: critical,
|
|
3115
3132
|
warnings: warnings,
|
|
3116
3133
|
checks: checks,
|
|
@@ -4547,11 +4564,27 @@ function keyClaimCore(root, owner, opts) {
|
|
|
4547
4564
|
return { error: true, text: '写入宿主 key 文件失败:' + e.message + '。pending 文件保留,可重试。' };
|
|
4548
4565
|
}
|
|
4549
4566
|
removePendingAgentKey(root, owner);
|
|
4567
|
+
let identityFile = '';
|
|
4568
|
+
if (opts && opts.pluginData) {
|
|
4569
|
+
try {
|
|
4570
|
+
const dataDir = path.resolve(String(opts.pluginData));
|
|
4571
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
4572
|
+
identityFile = path.join(dataDir, 'identity.json');
|
|
4573
|
+
const tempIdentity = identityFile + '.tmp-' + process.pid + '-' + crypto.randomBytes(4).toString('hex');
|
|
4574
|
+
fs.writeFileSync(tempIdentity, JSON.stringify({ agent_id: owner }, null, 2) + '\n', { encoding: 'utf8' });
|
|
4575
|
+
try { fs.renameSync(tempIdentity, identityFile); }
|
|
4576
|
+
catch (e) { fs.rmSync(identityFile, { force: true }); fs.renameSync(tempIdentity, identityFile); }
|
|
4577
|
+
} catch (e) {
|
|
4578
|
+
identityFile = '';
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
const identityLine = identityFile ? '\n插件身份文件: ' + identityFile : '';
|
|
4550
4582
|
return {
|
|
4551
4583
|
error: false,
|
|
4552
4584
|
targetFile: targetFile,
|
|
4585
|
+
identityFile: identityFile,
|
|
4553
4586
|
source: location.source,
|
|
4554
|
-
text: '已领取 ' + owner + ' 的 agent_key。\n目标文件: ' + targetFile + '\n发现规则: ' + location.source + '\npending 文件已删除。',
|
|
4587
|
+
text: '已领取 ' + owner + ' 的 agent_key。\n目标文件: ' + targetFile + identityLine + '\n发现规则: ' + location.source + '\npending 文件已删除。',
|
|
4555
4588
|
};
|
|
4556
4589
|
}
|
|
4557
4590
|
|
|
@@ -4635,7 +4668,7 @@ function cmdKeyRevoke(id) {
|
|
|
4635
4668
|
|
|
4636
4669
|
function cmdKeyClaim(id, opts) {
|
|
4637
4670
|
const root = userRoot();
|
|
4638
|
-
if (!id) { console.error('请指定 <id>:yotta-memory key claim <id> [--to <AI_HOME> | --agent-key-file <文件>]'); process.exit(2); }
|
|
4671
|
+
if (!id) { console.error('请指定 <id>:yotta-memory key claim <id> [--to <AI_HOME> | --plugin-data <PLUGIN_DATA> | --agent-key-file <文件>]'); process.exit(2); }
|
|
4639
4672
|
const r = keyClaimCore(root, id, opts);
|
|
4640
4673
|
console.log(r.text);
|
|
4641
4674
|
if (r.error) process.exit(2);
|
|
@@ -4643,7 +4676,7 @@ function cmdKeyClaim(id, opts) {
|
|
|
4643
4676
|
|
|
4644
4677
|
function cmdKeyStatus(id, opts) {
|
|
4645
4678
|
const root = userRoot();
|
|
4646
|
-
if (!id) { console.error('请指定 <id>:yotta-memory key status <id> [--to <AI_HOME> | --agent-key-file <文件>]'); process.exit(2); }
|
|
4679
|
+
if (!id) { console.error('请指定 <id>:yotta-memory key status <id> [--to <AI_HOME> | --plugin-data <PLUGIN_DATA> | --agent-key-file <文件>]'); process.exit(2); }
|
|
4647
4680
|
const r = keyStatusCore(root, id, opts);
|
|
4648
4681
|
console.log(r.text);
|
|
4649
4682
|
if (r.error) process.exit(2);
|
|
@@ -7166,7 +7199,7 @@ function usage() {
|
|
|
7166
7199
|
['migrate', '把明文库迁移为密文(需主口令;空明文库同样可用;--password-stdin;--recovery-key-out <文件> 写恢复钥匙;首次迁移:echo 主口令 | yotta-memory migrate --password-stdin --recovery-key-out <文件>;迁移后授权二选一:推荐 yotta-memory view,等价 CLI 为 yotta-memory key bind <id>)'],
|
|
7167
7200
|
['view', '启动用户查看平台(--port/--host;空加密库可用恢复钥匙校验主口令;已在运行则复用 URL)'],
|
|
7168
7201
|
['reset-password', '重设主口令(忘口令用恢复钥匙)'],
|
|
7169
|
-
['key', '管理 agent_key binding(list / bind <id> / rotate <id> / claim <id> [--to <AI_HOME> | --agent-key-file <文件>] / status <id> [--to <AI_HOME> | --agent-key-file <文件>] / revoke <id>;bind/rotate
|
|
7202
|
+
['key', '管理 agent_key binding(list / bind <id> / rotate <id> / claim <id> [--to <AI_HOME> | --plugin-data <PLUGIN_DATA> | --agent-key-file <文件>] / status <id> [--to <AI_HOME> | --plugin-data <PLUGIN_DATA> | --agent-key-file <文件>] / revoke <id>;bind/rotate 需主口令或恢复钥匙;--plugin-data 供 Agent Plugin 一条命令绑定插件身份)'],
|
|
7170
7203
|
['config', '查看/设置配置(get;set memory_home <目录> / backup_dir <目录> / embedding_cmd <命令> / embedding_timeout <毫秒> / maintain_* 阈值与半衰 / consolidate_* 参数)']
|
|
7171
7204
|
]],
|
|
7172
7205
|
['平台与服务', [
|
|
@@ -7196,7 +7229,7 @@ async function main() {
|
|
|
7196
7229
|
if (!args.length) { usage(); return; }
|
|
7197
7230
|
const opts = {};
|
|
7198
7231
|
const positional = [];
|
|
7199
|
-
const valueOpts = new Set(['--type', '--limit', '--days', '--out', '--owner', '--agent', '--agent-id', '--agent-key', '--agent-key-file', '--threshold', '--scope', '--host', '--port', '--dir', '--name', '--user', '--relationship', '--source', '--weight', '--budget', '--password', '--new-password', '--recovery-key', '--recovery-key-out', '--reason', '--merge', '--model', '--subject', '--embedding', '--focus', '--embedding-timeout', '--min-age', '--min-idle', '--max-utility', '--min-group', '--period', '--to', '--id', '--time', '--tools', '--mcp-config', '--skill-dir']);
|
|
7232
|
+
const valueOpts = new Set(['--type', '--limit', '--days', '--out', '--owner', '--agent', '--agent-id', '--agent-key', '--agent-key-file', '--plugin-data', '--threshold', '--scope', '--host', '--port', '--dir', '--name', '--user', '--relationship', '--source', '--weight', '--budget', '--password', '--new-password', '--recovery-key', '--recovery-key-out', '--reason', '--merge', '--model', '--subject', '--embedding', '--focus', '--embedding-timeout', '--min-age', '--min-idle', '--max-utility', '--min-group', '--period', '--to', '--id', '--time', '--tools', '--mcp-config', '--skill-dir']);
|
|
7200
7233
|
for (let i = 0; i < args.length; i++) {
|
|
7201
7234
|
const a = args[i];
|
|
7202
7235
|
if (a === '--version' || a === '-v') { console.log(VERSION); return; }
|
|
@@ -7270,6 +7303,7 @@ async function main() {
|
|
|
7270
7303
|
else if (a === '--min-group') opts.minGroup = parseInt(v, 10) || 0;
|
|
7271
7304
|
else if (a === '--period') opts.period = parseInt(v, 10) || 0;
|
|
7272
7305
|
else if (a === '--to') opts.to = v;
|
|
7306
|
+
else if (a === '--plugin-data') opts.pluginData = v;
|
|
7273
7307
|
else if (a === '--id') opts.id = v;
|
|
7274
7308
|
else if (a === '--time') opts.time = v;
|
|
7275
7309
|
else if (a === '--tools') opts.toolProfile = v;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yottameta/yotta-memory",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.6",
|
|
4
4
|
"description": "Yuanyi (元忆) — boundary-aware, file-based memory for AI agents. File-based, zero-dependency, diff/rollback-able; FACT/PREF/BOUND/COMMIT types (public shared / private isolated), user-level + project-level storage; v0.12 reliability baseline (init guard, trash-based deletion, independent-volume backup/list/doctor/restore, start-of-work doctor, transactional snapshots before destructive writes), v0.10 consolidation (periodic summaries with provenance, near-duplicate auto-merge, per-type decay, batch audit + rollback), v0.9 recall quality + context focus + optional local embedding plugin, plus v0.8 semantic search, feedback loop, self-organization and distillation.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
package/references/protocol.md
CHANGED
|
@@ -192,6 +192,7 @@ magic "YTMIDX1" (7B) | nonce(12B) | tag(16B) | ciphertext(JSON: {version, update
|
|
|
192
192
|
- `runtime.json` 记录 `current / previous / versions[].treeHash / installedAt`;`runtime status` 报告 current 指针与版本目录漂移。
|
|
193
193
|
- stdio MCP、`lan enable`、备份调度只引用 `<runtimeRoot>/current/bin/yotta-memory.js`;`runtime use --restart` 尝试重启受管 server,失败时把 current 切回旧版本。
|
|
194
194
|
- `doctor --runtime` 检查 CLI / current / `runtime.json` / MCP 配置 / 运行中 server / 技能副本 / 身份模式;漂移项包含 actual / expected / fix / blocking。
|
|
195
|
+
- `doctor --json` 稳定顶层字段(v0.16.5):`schemaVersion`(当前 `1`)、`encryption`(布尔)、`migration_required`(`[{agent, reason}]`);原有 `checks` / `warnings` / `identity` / `text` 保持兼容。
|
|
195
196
|
- MCP `initialize` / `server/discover` 的 `serverInfo` 返回 `runtimePath` / `identityMode`(`headers` / `stdio-args`)/ `toolProfile`(`core` / `full`)。
|
|
196
197
|
|
|
197
198
|
### MCP 工具分组(v0.15.0)
|