@yottameta/yotta-memory 0.16.7 → 0.17.0

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,3 +1,51 @@
1
+ ## v0.17.0 (2026-09-25)
2
+
3
+ **帮助改造(A)**
4
+
5
+ - 顶层 `--help` 重排为四段(核心记忆 / 身份与画像 / 加密与安全 / 平台与服务),逐条列出命令、子命令路径与全部选项;每个选项给出「做什么 / 什么时候用 / 注意」三段中文说明,风险选项(`--no-encrypt` / `--unsafe` / `--apply` / `--force` / `--purge` / `--allow-same-volume`)必须带「注意」。
6
+ - 帮助文案收敛到单一真源 `HELP_MODEL`(`usage()` 只做渲染),解析器侧 `CLI_FLAG_OPTS` / `CLI_VALUE_OPTS` 上移为模块级名单;新增 `test/help-coverage.test.js` 四件护栏(命令 / 子命令覆盖、帮助 ↔ 解析器双向一致、风险项必须带注意、`main()` 布尔字面量必须登记)+ 渲染快照,禁止两处手写文案漂移。
7
+
8
+ **规模三项(B1 写入分层 + B2 规模体检)**
9
+
10
+ - 记忆文件新写入按年/月分层:公共 `facts/<yyyy>/<mm>/`,私密 `private/<owner>/<type>/<yyyy>/<mm>/`。读取与索引递归兼容新旧两种布局,v0.16 及更早的平铺文件保持原位、不自动迁移。
11
+ - 去重与序号跨布局统一:序号在「类型目录 + owner」内全局唯一(平铺与分层不重复编号);写入去重只扫当前年/月、同年平铺文件与类型根,避免大库每次写入全量遍历(跨月重复由既有的 `maintain --dedup` 与 `consolidate` 处理)。
12
+ - 归档保留分层:`archive` / `maintain --apply --purge` / `consolidate` 移入 `.archive/` 时按原年/月路径落位,不同月份的同名文件不再互相覆盖;旧平铺文件仍落到归档根。
13
+ - 明文库转加密(`migrate`)递归处理年/月子目录,不再漏掉分层私密文件。
14
+ - 平铺 / 分层同序号:条目身份 = 类型 + owner + 文件名(`YYYY-MM-DD-NNNN.md`),与存放位置无关;公共 FACT 的 owner 取自 frontmatter,不同 owner 的同序号文件不误报。内容摘要相同 → 只索引一次;内容不同 → 两份都保留可读,`doctor` 新增 `checks.layout` 与路径告警;新写入永不复用已占用的序号。加密条目在当前密钥不可用时按「待核」处理,不静默丢弃任何一份。
15
+ - `doctor` 新增规模体检:记忆条数 / 单目录最大文件数 / 索引总体积 / 索引冷启动耗时(多次取中位数);阈值走 `config set scale_warn_entries` / `scale_warn_files_per_dir` / `scale_warn_index_bytes` / `scale_warn_cold_start_ms`,超阈值进 `checks.scale.warnings` 并计入 doctor warning,只读、不锁定破坏性写入。
16
+ - 回归:`test/scale-layout.test.js` 8 项(新写入分层 / 跨布局序号 / 新旧混读 / 导出导入往返 / 私密归属 / 归档路径 / doctor 规模正常与告警)。
17
+ - 升级提示:升到 0.17.0 后请用 **0.17.0 引擎**执行一次 `yotta-memory reindex`。0.16.7 及更早引擎不识别年/月分层目录,旧引擎重建索引会漏掉分层条目;本批去重只影响索引与告警,不自动删除、不移动、不覆盖磁盘文件。
18
+
19
+ **索引按需加载 + 基准评测(B3 + A1)**
20
+
21
+ - 索引按年份懒加载:新增 `loadIndexFor(root, { years })`;命中分片 manifest(`index-<year>.json`)时只读取指定年份的分片文件,`recall --year <yyyy>` / `context --year <yyyy>` 走该路径(可重复传多次),不传年份维持全量读取、既有行为零变化。命中后的访问计数回写(`touchIndex`)同样只碰命中年份的分片,其它年份分片逐字节不变。平铺索引(未达 5000 条分片阈值)无法少读文件,按条目年份过滤;`--year` 只接受四位年份,非法值给中文提示并 exit 2。
22
+ - 新增 `bench` 可复算基准评测:默认按库内条目做确定性抽样(固定种子,最多 20 条查询)生成基线评测集,也可用 `--evalset <文件>` 指定评测集 v1(`{ "version": 1, "queries": [ { "query": "...", "expect": ["<记忆 id>"] } ] }`,记忆 id 可写相对路径或文件名)。
23
+ - 指标 = `Recall@k` / `MRR` / `nDCG@k` / `HitRate` + 固定种子 bootstrap 95% 置信区间;报告写明库指纹(条数 + 索引 SHA-256 + 评测集 SHA-256)与参数,默认不含墙钟时间——同库 + 同评测集 + 同参数必须同输出。`--ablate` 给关键词 / 语义 × 融合(0.65 语义 + 0.35 效用)/ 纯分四组消融;`--gate <指标>=<数值>` 供 CI(不达标 exit 1,指标可选 `recall` / `mrr` / `ndcg` / `hit`);`--timing` 显式附带检索耗时 p50 / p95(带上后报告标记为不可逐字节复算)。
24
+ - `bench` 全程只读:索引缺失或版本过旧时提示先 `reindex`(不代建索引)、不写访问计数、不调用外部 embedding 插件;评测集非法(版本 / 空 query / 空 expect / 非法 JSON / 文件不存在)分别给中文修复建议并 exit 2;对当前身份不可读的记忆计入 `corpus.denied` 并跳过。
25
+ - 检索打分与排序抽成共享原语 `scoreCandidates` / `rankHits`,`recall` 与 `bench` 走同一套逻辑,避免「评测口径」与真实检索漂移;recall 自身行为逐字节不变。
26
+ - 帮助与回归:`--help` 新增 `bench` 命令与 `--year` / `--evalset` / `--k` / `--seed` / `--bootstrap` / `--ablate` / `--gate` / `--timing` 逐项中文说明;新增 `test/index-lazy-year.test.js` 5 项(分片读取集合 / 无年份全量一致 / 平铺过滤 / recallCore 年份 / CLI `--year` 与非法年份)+ `test/bench.test.js` 8 项(指标手算 / 复算与只读 / 索引指纹 / 门禁 / 消融 / 评测集与索引校验 / `--out` / 文本与 `--timing`);全量 `npm test` 196/196 PASS(0.16.7 基线 171)。
27
+
28
+ **恢复探针 + 记忆库安全扫描(A2 + A4)**
29
+
30
+ - 新增恢复 / 迁移基线探针:`doctor --baseline [--against <库路径>] [--template <文件>]`,`backup drill <id> --probe [--against <库路径>]`。六类固定探针 = ① 身份(`agents.json` / `iam` 在位)② 近期(最近条目可召回)③ 仅源库独有(`--against` 差集条目必须已在目标库)④ CJK(中文条目可召回)⑤ 操作规则(`BOUND` 类可读)⑥ owner 范围(各 owner 计数 + 无法读取文件清单);任何一项失败都会列出缺失清单并以非零状态退出(`doctor` exit 2、`drill` 判失败)。探针内容由确定性抽样或用户模板生成,**不硬编码任何具体记忆**。
31
+ - 探针全程只读:直接读记忆文件(不依赖可能过期的索引)、不重建索引、不写访问计数、不调用外部 embedding。`doctor --baseline` 的探针结果进 `checks.baseline`(`probes` / `counts` / `unreadable` / `ok`),不带 `--baseline` 时 `doctor` 既有语义与输出不变;`backup drill` 不带 `--probe` 时行为与旧版一致(成功返回新增 `probes: null`)。
32
+ - 探针模板 v1(`--template <文件>`)只加严判定、不放宽:`{ "version": 1, "expect_owners": [], "expect_min_entries": 0, "expect_types": { "BOUND": 1 }, "queries": [ { "id": "...", "query": "...", "expect": ["<记忆 id>"] } ] }`;模板文件不存在 / 非法 JSON / 版本不支持 / 类型或条数非法都给出中文修复建议并 exit 2。
33
+ - 条目身份键与布局无关(`类型/owner/文件名`),旧平铺 `facts/x.md` 与新年/月分层指向同一条记忆时不会误报「缺失」,因此 `--against` 可直接用于旧库 → 新库的迁移验收。
34
+ - 新增 `scan` 记忆库安全扫描:`yotta-memory scan [--path <目录>] [--gate <安全级别>] [--quarantine --yes] [--restore] [--id <批次>] [--json]`。七类检测 = 恶意指令 / Prompt 注入 / 凭证泄漏 / 数据外泄 / 护栏绕过 / 行为操纵 / 权限提升;五级 `safe → low → medium → high → critical`;每条命中给 `file:line` 证据与规则出处。
35
+ - 扫描默认**只报告**:不改写任何文件、不自动隔离、不自动删除、零网络零依赖。`--gate` 命中该级别及以上 exit 1(`--gate safe` 表示任何命中都不允许),非法级别 exit 2;`--path` 可指向另一个记忆库或导出目录(递归扫 `.md` / `.md.enc`,跳过 `.git` / `node_modules` / 隔离目录)。`.md.enc` 后缀但内容其实是明文的文件(历史恢复残留)不会被当成密文跳过,按文本扫描并计入 `summary.mislabelled`;每条命中除 `file:line` 外给出命中片段前后各 40 字符与命中原文(凭证类打码),长行也能一眼看到命中在哪。
36
+ - `scan --quarantine` 需要显式确认(`--yes` 或交互 `y/N`;非交互环境未确认时 exit 2 且不改文件):先把原文件逐字节备份到 `.memory-scan/quarantine/<批次>/` 并写 `manifest.json`,再把命中行替换为 `[已隔离: <规则> <类别>]`;`scan --restore [--id <批次>]` 还原最近(或指定)批次,批次已还原则拒绝重复还原。加密条目(`.md.enc`)在无授权密钥时不扫描,只计入 `summary.encrypted`。`scan` 是库主人的维护命令,会读整库文件(含其它 owner 的私密目录):智能体不应用它查看其它智能体的私密内容,跨 owner 扫描前先取得用户授权。
37
+ - 凭证类命中的片段一律打码(`[已打码]`),报告与 JSON 都不会回显密钥原文;规则词表不另起一套:每条规则的 `ref` 指向家族规则表的原始规则 id(`PIJ-xxx@yotta-verify` / `github@yotta-secret` / `DEX-001@yotta-security-audit` / `CMD-*@yotta-guardian`),`test/memory-scan.test.js` 在源码仓库内逐条回查这些规则 id 在对应技能里是否仍存在(发布产物内自动跳过该用例)。分工口径:元钥扫源码仓库、元信扫技能包、元忆扫记忆库。
38
+ - 帮助与回归:`--help` 新增 `doctor --baseline` / `--against` / `--template`、`backup drill --probe` 与 `scan` 的逐项中文说明(风险项 `--quarantine` / `--restore` / `--yes` 均带「注意」);新增 `test/baseline-probe.test.js` 7 项(六类探针 / 身份缺失变红 / 差集缺失清单 / 模板期望 / 模板校验 / 只读 / `drill --probe`)+ `test/memory-scan.test.js` 9 项(七类命中 / 证据行号与出处 / 凭据打码 / 门禁 / 加密跳过与 `--path` / 只读 / 隔离与还原 / 规则出处回查);全量 `npm test` 212/212 PASS(0.16.7 基线 171 + S2–S5 新增 41)。
39
+
40
+ **彻底删除 AI 身份与私密记忆(identity remove)**
41
+
42
+ - 新增 `yotta-memory identity remove <id> [--dry-run] [--yes] [--keep-memories] [--keep-identity]`,并在用户查看平台 `view` 的 AI 列表里加「删除」按钮:某个 AI 不再使用时,一次把它清干净——① `agents.json` 身份登记 ② `keys/<id>.key.enc`(owner 密钥与恢复侧文件)③ `keys/bindings/<id>.key.agent` 授权绑定 ④ `keys/pending/<id>.key` 待领取 key ⑤ `keys/cache/<id>.key` 明文缓存 ⑥ `private/<id>/` 整个目录(私密记忆 + owner 索引 + profile / distill)⑦ `.server/tokens.json` 里的 token ⑧ `grants.json` 里的授权引用 ⑨ 重建索引并写审计。**公共明文 FACT 不删**(共享事实),其它 owner 零影响。
43
+ - 语义:**真删**(不可恢复)。删掉 owner 密钥后,该 owner 现存密文在密码学上也不可再解;需要保留记忆时用 `--keep-memories`(只注销身份与授权),需要保留登记时用 `--keep-identity`(只清私密记忆与授权)。`--dry-run` 先列清单且只读。
44
+ - 权限边界:**只能由用户本人执行**。加密库要求提供主口令(能解开任一 owner key 或恢复材料)或 `--recovery-key`;明文库没有可校验的用户凭据,要求显式 `--agent user`;`view` 里已用主口令解锁的会话视为用户本人。AI 用自身身份调用一律拒绝——AI 不得删除自己或别的 AI 的身份。
45
+ - 破坏性闸门:走既有 `doctor` + 独立备份 + 事务快照口径(未配置独立备份目录、或 doctor 严重项时直接拒绝),执行前写 `transaction_start`、执行后写 `identity_remove` 审计(含快照 id、授权方式、删除清单)。CLI 交互需输入完整 id 确认,或显式 `--yes`;`view` 侧要求确认串等于完整 agent ID。
46
+ - 回归:新增 `test/identity-remove.test.js` 9 项(九步清单真删 / 公共明文与其它 owner 零变化 / `--dry-run` 只读 / 拒绝 AI 身份 / 加密库口令校验 / 明文库用户身份与备份闸门 / 幂等 / 两个保留开关 / view 端点确认串与闸门);全量 `npm test` 221/221 PASS。
47
+ - 回归:新增 `test/layout-collision.test.js` 5 项(相同摘要去重 / 冲突双保留与路径告警 / 不同日期不误报 / 不同 owner 不误报 / 加密待核不丢弃);全量 `npm test` 226/226 PASS。
48
+
1
49
  ## v0.16.7 (2026-09-23)
2
50
 
3
51
  **迁移口令安全 + view 根指纹复用校验**
package/README.md CHANGED
@@ -23,7 +23,8 @@
23
23
 
24
24
  > 📖 The user-facing operations manual lives in [USER_GUIDE.md](USER_GUIDE.md).
25
25
 
26
- > 🆕 **v0.16.7 (migration password safety + view root fingerprint)**: use the interactive migration prompt `yotta-memory migrate --recovery-key-out "%USERPROFILE%\yotta-memory-recovery.key"` and type the master password. Automation can set `YOTTA_MEMORY_PASS` with an ASCII password. Do not pipe non-ASCII passwords on Windows (`echo 中文 | ...` can change the bytes). `view` now verifies a memory-home fingerprint before reusing a running server and refuses cross-store or legacy servers without one.
26
+ > 🆕 **v0.17.0 (scale: year/month layout + doctor scale check + lazy index + bench)**: new entries are written into year/month folders — public `facts/<yyyy>/<mm>/`, private `private/<owner>/<type>/<yyyy>/<mm>/`. Flat files from v0.16 and earlier stay in place and remain readable; nothing is migrated automatically. Archiving keeps the year/month path, so same-named files from different months no longer overwrite each other. `doctor` gained a scale section (entry count / largest directory / index size / index cold start) with thresholds set through `config set scale_warn_entries` / `scale_warn_files_per_dir` / `scale_warn_index_bytes` / `scale_warn_cold_start_ms`; exceeding a threshold warns only and never locks destructive writes. Large stores can read only the shards of a given year: `recall --year <yyyy>` / `context --year <yyyy>` (repeatable; omitting it loads everything exactly as before). New `bench` command: deterministic auto sampling or `--evalset <file>` (evalset v1), reporting Recall@k / MRR / nDCG@k / HitRate with bootstrap 95% CI plus store and evalset fingerprints; `--gate <metric>=<value>` fits CI, and the same store + evalset + parameters always produce the same output. `bench` is read-only: it never rebuilds the index, never touches access counters and never calls an external embedding plugin. Previous v0.16.7: interactive `yotta-memory migrate --recovery-key-out` prompt, `YOTTA_MEMORY_PASS` for automation, and a `view` memory-home fingerprint before reusing a running server.
27
+ > 🆕 **v0.17.0 (recovery probe + memory-store scan)**: `doctor --baseline [--against <store>] [--template <file>]` and `backup drill --probe` run six read-only baseline probes (identity / recent / source-only diff / CJK / operation rules / owner scope) against the target store or restored copy. Entry identity keys are layout-independent, so an old flat store migrating into the year/month layout never reports false gaps; missing items are listed and exit non-zero (`doctor` exit 2 / `drill` fails). Probes never hard-code any memory and `--template` only tightens the verdict. New `scan` command: seven classes (malicious instruction / prompt injection / credential leak / data exfiltration / guardrail bypass / behaviour manipulation / privilege escalation), five severities and `file:line` evidence; report-only by default, zero network and zero dependencies. `--gate` exits 1 at or above the given severity; `--quarantine` needs `--yes` or interactive confirmation and backs up each original file byte-for-byte into `.memory-scan/quarantine/` before redacting hit lines, with `--restore` to roll back; credential snippets are always masked.
27
28
  > 🆕 **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.
28
29
  > 🆕 **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.
29
30
  > 🆕 **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.
@@ -264,6 +265,8 @@ If you installed the CLI globally, `npm i -g @yottameta/yotta-memory` updates bo
264
265
 
265
266
  After updating, verify `yotta-memory --version` and the installed `yotta-memory/SKILL.md` frontmatter `version:`.
266
267
 
268
+ > **v0.17.0 upgrade note**: run `yotta-memory reindex` once with the 0.17.0 engine after upgrading. Engines 0.16.7 and earlier do not understand the new year/month layout and will drop layered entries from a rebuilt index. `doctor` now reports flat/layered same-identity duplicates: identical copies are indexed once; conflicting copies stay readable and are listed with both paths, and new writes never reuse an occupied sequence number.
269
+
267
270
  **v0.10.0 upgrade notes** — upgrading touches no data: no migration, no reindex, no re-init needed. v0.10.0 does not change the memory file format, the `facts/` / `private/<owner>/<type>/` layout, or the index version, so existing stores open as-is.
268
271
 
269
272
  Behavior changes to be aware of:
@@ -284,13 +287,14 @@ Optional post-upgrade self-check: `yotta-memory config get` (confirm `memory_hom
284
287
  |---|---|
285
288
  | `yotta-memory init [--project] [--dir <dir>]` | Initialize the store (default user-level `~/.yottamemory/`; --dir sets an explicit location) |
286
289
  | `yotta-memory remember <type> <subject> <statement> [--owner <id>] [--source <src>] [--weight <0..>] [--verify] [--no-hint]` | Write a memory (same subject+statement auto-updates; --owner marks ownership; --source records origin; --weight importance, dedup takes max; --verify read-back; --no-hint disables type hints) |
287
- | `yotta-memory recall [keywords] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <cmd>] [--embedding-timeout N]` | Search memory (semantic + utility ranking; optional local embedding plugin; partitioned reads; cross-reading other agents' private is denied by default, needs grant / identity=user / `--unsafe`; project-level priority) |
290
+ | `yotta-memory recall [keywords] [--type T] [--limit N] [--year <yyyy>] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <cmd>] [--embedding-timeout N]` | Search memory (semantic + utility ranking; optional local embedding plugin; partitioned reads; cross-reading other agents' private is denied by default, needs grant / identity=user / `--unsafe`; project-level priority; since v0.17.0 `--year` reads only the shards of that year, repeatable) |
288
291
  | `yotta-memory profile [--owner <id>]` | Generate a user profile (aggregates `private/<owner>` verbatim, zero inference, writes `profile.md`; cross-owner denied by default) |
289
- | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <text>] [--explain] [--embedding <cmd>]` | Generate the start-of-work package (identity + rules + profile + long-term summaries + task-focused memory + recent corridor + high-value backfill + boundaries + commitments + session loop contract; --budget caps dynamic memory, --focus adds task relevance, --explain shows included/dropped) |
292
+ | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <text>] [--year <yyyy>] [--explain] [--embedding <cmd>]` | Generate the start-of-work package (identity + rules + profile + long-term summaries + task-focused memory + recent corridor + high-value backfill + boundaries + commitments + session loop contract; --budget caps dynamic memory, --focus adds task relevance, --year limits it to given years, --explain shows included/dropped) |
290
293
  | `yotta-memory forget <file>` | Delete a memory (by type-dir path or file name) |
291
- | `yotta-memory doctor [--json] [--runtime] [--mcp-config <file>] [--skill-dir <dir>]` | Start-of-work reliability check (store / key material / index / identity / latest backup; critical issues lock destructive writes); `--runtime` checks CLI / current / MCP config / running server / skill-copy drift |
294
+ | `yotta-memory doctor [--json] [--runtime] [--mcp-config <file>] [--skill-dir <dir>] [--baseline [--against <store>] [--template <file>]]` | Start-of-work reliability check (store / key material / index / identity / latest backup; critical issues lock destructive writes); `--runtime` checks CLI / current / MCP config / running server / skill-copy drift; `--baseline` adds the six read-only recovery / migration probes and exits 2 with a missing-item list |
292
295
  | `yotta-memory archive [--days 180] [--threshold 0.4]` | Archive old memory (decay-blended utility + age; immutable / BOUND exempt; private to `.archive/private/<owner>/<type>/`) |
293
296
  | `yotta-memory reindex` | Rebuild the index (after manually editing .md) |
297
+ | `yotta-memory identity remove <id> [--dry-run] [--yes] [--keep-memories] [--keep-identity] [--password <pass> \| --recovery-key <key>]` | Permanently delete one AI identity and its private memories (v0.17.0): identity registration, owner key, agent binding, pending key, plaintext cache, the whole `private/<id>/` tree, tokens and grant references, then rebuild the index and write an audit record. Public plaintext FACTs are kept and other AIs are untouched. User-only: an encrypted store requires the master password or recovery key, a plaintext store requires an explicit `--agent user`, and the unlocked `view` session counts as the user. Destructive gate = doctor + independent backup + transaction snapshot; `--dry-run` lists the plan only |
294
298
  | `yotta-memory export [--out f.json]` / `import <f.json>` | Export / import |
295
299
  | `yotta-memory config set <key> <value>` / `config get` | Store location and engine tuning (`memory_home` / `embedding_cmd` / `embedding_timeout` / `maintain_archived_utility` / `maintain_decay_halflife_<TYPE>` / `consolidate_*`) |
296
300
  | `yotta-memory whoami` | Show the current agent identity and registration status |
@@ -303,6 +307,8 @@ Optional post-upgrade self-check: `yotta-memory config get` (confirm `memory_hom
303
307
  | `yotta-memory feedback <file> --useful|--useless [--reason <r>] [--undo]` | Usage feedback (useful/useless adjusts weight / confidence / feedback_net; --undo rolls back the last one) |
304
308
  | `yotta-memory distill [--owner <id>] [--subject <topic>] [--model <cmd>] [--out <path>]` | Psychological-log distillation (stats / topic profile / knowledge map; optional local model, local CLI only) |
305
309
  | `yotta-memory explain <file>` | Show the utility breakdown and archive / forget / BOUND-exempt status of one memory |
310
+ | `yotta-memory bench [--evalset <file>] [--k N] [--seed N] [--bootstrap N] [--ablate] [--gate <metric>=<value>] [--timing] [--year <yyyy>] [--json] [--out <file>]` | Reproducible retrieval benchmark (v0.17.0): deterministic auto sampling from the store or an explicit evalset v1; reports Recall@k / MRR / nDCG@k / HitRate with bootstrap 95% CI plus store and evalset fingerprints, and writes no wall-clock data by default; `--ablate` compares lexical / semantic × fused / pure-score; `--gate` fails the run (exit 1) when a metric is below the threshold; `--timing` adds p50 / p95 and marks the report as not byte-reproducible. Read-only: no index rebuild, no access counters, no external embedding plugin |
311
+ | `yotta-memory scan [--path <dir>] [--gate <severity>] [--quarantine --yes] [--restore] [--id <batch>] [--json]` | Memory-store security scan (v0.17.0): seven classes = malicious instruction / prompt injection / credential leak / data exfiltration / guardrail bypass / behaviour manipulation / privilege escalation, five severities with `file:line` evidence and rule provenance; report-only by default, zero network and zero dependencies; `--gate` fails the run (exit 1) at or above the given severity; `--quarantine` needs `--yes` or interactive confirmation, backs each original file up byte-for-byte into `.memory-scan/quarantine/` and then redacts hit lines, and `--restore` rolls it back; credential snippets are always masked |
306
312
 
307
313
  Types: `FACT` (fact, public shared) / `PREF` (preference) / `BOUND` (boundary) / `COMMIT` (commitment).
308
314
 
package/README.zh-CN.md CHANGED
@@ -23,7 +23,8 @@
23
23
 
24
24
  > 📖 面向用户的操作手册见 [USER_GUIDE.md](USER_GUIDE.md)。
25
25
 
26
- > 🆕 **v0.16.7(迁移口令安全 + view 根指纹)**:明文库转加密推荐交互式 `yotta-memory migrate --recovery-key-out "$env:USERPROFILE\yotta-memory-recovery.key"`,按提示输入主口令;自动化使用 `YOTTA_MEMORY_PASS`。非 ASCII 口令不要用 Windows 管道(`echo 中文 | ...` 可能改变实际口令)。`view` 复用端口前会校验 memory_home 指纹;跨库或旧版无指纹服务会拒绝复用并提示换端口。
26
+ > 🆕 **v0.17.0(规模:文件分层 + doctor 规模体检 + 索引按需加载 + bench 基准评测)**:新写入按年/月分层——公共 `facts/<年>/<月>/`、私密 `private/<owner>/<type>/<年>/<月>/`;v0.16 及更早的平铺文件留在原位继续可读,不做自动迁移。归档保留分层,不同月份的同名文件不会互相覆盖。`doctor` 新增规模段(记忆条数 / 单目录最大文件数 / 索引总体积 / 索引冷启动耗时),阈值用 `config set scale_warn_entries` / `scale_warn_files_per_dir` / `scale_warn_index_bytes` / `scale_warn_cold_start_ms` 调整,超阈值只告警,不锁定破坏性写入。大库检索可以按年份只读对应分片:`recall --year <yyyy>` / `context --year <yyyy>`(可重复传多次,不传即全量、行为与旧版一致)。新增 `bench` 可复算基准评测:默认按库内条目确定性抽样,`--evalset <文件>` 也可指定评测集;输出 Recall@k / MRR / nDCG@k / HitRate + 95% 置信区间、库指纹与评测集指纹,`--gate <指标>=<数值>` 可接 CI,同库同评测集同参数必得同结果;全程只读,不重建索引、不写访问计数、不调用外部 embedding。上一版 v0.16.7:明文库转加密推荐交互式 `yotta-memory migrate --recovery-key-out "$env:USERPROFILE\yotta-memory-recovery.key"`,自动化使用 `YOTTA_MEMORY_PASS`;`view` 复用端口前校验 memory_home 指纹。
27
+ > 🆕 **v0.17.0(恢复探针 + 记忆库安全扫描)**:`doctor --baseline [--against <库路径>] [--template <文件>]` 与 `backup drill --probe` 在目标库 / 恢复副本上跑六类只读基线探针(身份 / 近期 / 仅源库独有 / CJK / 操作规则 / owner 范围);条目身份键与布局无关,旧平铺 → 新年/月分层的迁移不会误报「缺失」;缺失项列出清单并非零退出(`doctor` exit 2 / `drill` 判失败),探针不硬编码任何记忆,`--template` 只加严判定。新增 `scan` 记忆库安全扫描:七类(恶意指令 / Prompt 注入 / 凭证泄漏 / 数据外泄 / 护栏绕过 / 行为操纵 / 权限提升)+ 五级分级 + `file:line` 证据,默认只报告、零网络零依赖;`--gate` 命中该级别及以上 exit 1;`--quarantine` 需 `--yes` 或交互确认,先把原文件逐字节备份到 `.memory-scan/quarantine/` 再替换命中行,`--restore` 还原;凭证片段一律打码不回显。
27
28
  > 🆕 **v0.16.5(doctor JSON 契约)**:`doctor --json` 顶层新增稳定字段 `schemaVersion` / `encryption` / `migration_required`,同时保留原有 `checks` / `warnings` / `identity` 结构。
28
29
  > 🆕 **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`。
29
30
  > 🆕 **v0.16.2(首启修复)**:空加密库 `view` 可用恢复钥匙解锁;非 TTY 支持 `--password-stdin`;恢复钥匙支持 `--recovery-key-out <文件>`;`--agent-key-file` 不存在时降级未授权(公共 FACT 可读、私密 fail-closed);空明文库可直接 `migrate` 启用加密;`view` 端口占用给明确提示。
@@ -303,6 +304,8 @@ bash install.sh --agent <智能体名称>
303
304
 
304
305
  升级后请核对 `yotta-memory --version` 和已安装的 `yotta-memory/SKILL.md` frontmatter 中的 `version:`。
305
306
 
307
+ > **v0.17.0 升级提示**:升级后请用 0.17.0 引擎执行一次 `yotta-memory reindex`。0.16.7 及更早引擎不识别年/月分层目录,旧引擎重建索引会漏掉分层条目。`doctor` 会报告平铺 / 分层同序号:内容相同的两份只索引一次;内容不同的两份都保留可读并给出路径告警;新写入不复用已占用的序号。
308
+
306
309
  **v0.10.0 升级提示**——升级不碰数据:无需迁移 / reindex / 重新 init。v0.10.0 没有改记忆文件格式、`facts/` 与 `private/<owner>/<type>/` 布局,也没有改索引版本,旧库打开即用。
307
310
 
308
311
  需要知道的 4 条行为变化:
@@ -325,13 +328,14 @@ bash install.sh --agent <智能体名称>
325
328
  |---|---|
326
329
  | `yotta-memory init [--project] [--dir <目录>]` | 初始化记忆库(默认用户级 `~/.yottamemory/`;--dir 显式指定位置)|
327
330
  | `yotta-memory remember <type> <subject> <statement> [--owner <id>] [--source <来源>] [--weight <0..>] [--verify] [--no-hint]` | 写入记忆(同 subject+statement 自动更新;--owner 标注归属;--source 记录来源;--weight 重要性权重、去重取 max;--verify 写后回读;--no-hint 关闭类型提示)|
328
- | `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <命令>] [--embedding-timeout N]` | 检索记忆(语义+效用分排序;可选本地 embedding 插件;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;`--agent <其它>` 仅作身份声明、不授予跨读;项目级优先)|
331
+ | `yotta-memory recall [关键词] [--type T] [--limit N] [--year <yyyy>] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <命令>] [--embedding-timeout N]` | 检索记忆(语义+效用分排序;可选本地 embedding 插件;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;`--agent <其它>` 仅作身份声明、不授予跨读;项目级优先;v0.17.0 起 `--year` 只读该年份分片,可重复传多次)|
329
332
  | `yotta-memory profile [--owner <id>]` | 生成用户画像(聚合 `private/<owner>/` 原文,零推断,写 `profile.md`;跨 owner 默认拒绝)|
330
- | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--explain] [--embedding <命令>]` | 生成开工上下文包(身份 + 铁律 + 画像 + 长期摘要 + 任务相关记忆 + 近期走廊 + 近期高价值 + 边界 + 承诺 + 会话闭环契约;--budget 控制动态记忆字符预算;--focus 任务聚焦;--explain 输出 included/dropped 选择解释)|
333
+ | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--year <yyyy>] [--explain] [--embedding <命令>]` | 生成开工上下文包(身份 + 铁律 + 画像 + 长期摘要 + 任务相关记忆 + 近期走廊 + 近期高价值 + 边界 + 承诺 + 会话闭环契约;--budget 控制动态记忆字符预算;--focus 任务聚焦;--year 限定年份;--explain 输出 included/dropped 选择解释)|
331
334
  | `yotta-memory forget <文件>` | 删除一条记忆(按类型目录路径或文件名)|
332
- | `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>]` | 开工可靠性检查(根目录 / 密钥库 / 索引 / 身份 / 最近备份;严重异常时锁定破坏性写入;`--runtime` 检查 CLI / current / MCP 配置 / 运行中 server / 技能副本漂移)|
335
+ | `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>] [--baseline [--against <库路径>] [--template <文件>]]` | 开工可靠性检查(根目录 / 密钥库 / 索引 / 身份 / 最近备份;严重异常时锁定破坏性写入;`--runtime` 检查 CLI / current / MCP 配置 / 运行中 server / 技能副本漂移;`--baseline` 追加恢复 / 迁移六类只读探针,缺失项列出清单并 exit 2)|
333
336
  | `yotta-memory archive [--days 180] [--threshold 0.4]` | 归档旧记忆(分类型衰减效用分 + 年龄;immutable / BOUND 豁免;私密入 `.archive/private/<owner>/<type>/`)|
334
337
  | `yotta-memory reindex` | 重建索引(手动改 .md 后校正)|
338
+ | `yotta-memory identity remove <id> [--dry-run] [--yes] [--keep-memories] [--keep-identity] [--password <口令> \| --recovery-key <钥匙>]` | 彻底删除一个 AI 身份与私密记忆(v0.17.0):真删身份登记 / owner 密钥 / 授权绑定 / 待领取 key / 明文缓存 / `private/<id>/` 全部私密记忆 / token / grants 引用,并重建索引 + 写审计;**公共明文 FACT 保留**、其它 AI 零影响;只能由用户本人执行(加密库要主口令或恢复钥匙,明文库要显式 `--agent user`),`view` 的 AI 列表里也有「删除」按钮;破坏性闸门 = doctor + 独立备份 + 事务快照,`--dry-run` 只列清单 |
335
339
  | `yotta-memory export [--out f.json]` / `import <f.json>` | 导出 / 导入 |
336
340
  | `yotta-memory config set <键> <值>` / `config get` | 记忆库位置与引擎参数(`memory_home` / `embedding_cmd` / `embedding_timeout` / `maintain_archived_utility` / `maintain_decay_halflife_<TYPE>` / `consolidate_*` 等)|
337
341
  | `yotta-memory whoami --agent <id>` | 查看当前显式身份与登记状态;身份不从环境变量读取 |
@@ -344,6 +348,8 @@ bash install.sh --agent <智能体名称>
344
348
  | `yotta-memory feedback <文件|主题> --useful|--useless [--reason <原因>] [--undo]` | 使用反馈(useful/useless 调整 weight / confidence / feedback_net;`--undo` 回滚最近一次)|
345
349
  | `yotta-memory distill [--owner <id>] [--subject <主题>] [--model <cmd>] [--out <路径>]` | 心理日志蒸馏(统计摘要 / 主题画像 / 知识地图;可选本地模型,仅 CLI)|
346
350
  | `yotta-memory explain <文件|主题>` | 查看单条记忆效用分项与归档 / 遗忘 / BOUND 豁免状态 |
351
+ | `yotta-memory bench [--evalset <文件>] [--k N] [--seed N] [--bootstrap N] [--ablate] [--gate <指标>=<数值>] [--timing] [--year <yyyy>] [--json] [--out <文件>]` | 可复算检索基准评测(v0.17.0):默认按库内条目确定性抽样,或用 `--evalset` 指定评测集 v1;输出 Recall@k / MRR / nDCG@k / HitRate + bootstrap 95% 置信区间、库指纹与评测集指纹,默认不含墙钟时间;`--ablate` 对比关键词 / 语义 × 融合 / 纯分;`--gate` 不达标 exit 1;`--timing` 附带 p50 / p95 后不再逐字节可复算。全程只读:不重建索引、不写访问计数、不调用外部 embedding 插件 |
352
+ | `yotta-memory scan [--path <目录>] [--gate <安全级别>] [--quarantine --yes] [--restore] [--id <批次>] [--json]` | 记忆库安全扫描(v0.17.0):七类 = 恶意指令 / Prompt 注入 / 凭证泄漏 / 数据外泄 / 护栏绕过 / 行为操纵 / 权限提升;五级 + `file:line` 证据与规则出处;默认只报告、零网络零依赖;`--gate` 命中该级别及以上 exit 1;`--quarantine` 需 `--yes` 或交互确认,先把原文件逐字节备份到 `.memory-scan/quarantine/` 再替换命中行;`--restore` 还原;凭证片段打码不回显 |
347
353
 
348
354
  类型:`FACT`(事实,公共共享)/ `PREF`(偏好)/ `BOUND`(边界)/ `COMMIT`(承诺)。
349
355
 
package/SKILL.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: yotta-memory
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.7
3
+ description: 元忆 —— 有权限边界的文件式智能体记忆。文件式、零依赖、可 diff/可回滚:让任何 AI 智能体活过会话,开工 recall 恢复上下文、重要信息 remember 落盘、收工归档。类型体系 FACT(公共共享)/ PREF / BOUND / COMMIT(私密隔离)。触发:记住、别忘了、记一笔、记忆、remember、recall、跨会话、上次说到、续测、交接、归档、记忆盘、共享记忆、局域网记忆、画像、开工上下文、长期理解摘要、近期走廊、会话闭环、记忆守则、profile、context、越用越懂、语义检索、反馈、维护、蒸馏、feedback、maintain、distill、explain、自我学习、自我进化、自我提升、查看平台分页、recall 候选预过滤、任务相关记忆、--focus、--embedding、压缩遗忘、consolidate、周期摘要、自动合并、分类型衰减、回滚、备份、backup、防误删、doctor、事务快照、基线探针、恢复演练、记忆库安全扫描、scan
4
+ version: 0.17.0
5
5
  license: MIT
6
6
  ---
7
7
 
@@ -20,6 +20,9 @@ license: MIT
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
22
  - **doctor JSON 稳定契约(v0.16.5)**:`doctor --json` 顶层新增 `schemaVersion`(当前 `1`)、`encryption`(布尔)、`migration_required`(`[{agent, reason}]`)。原有 `checks` / `warnings` / `identity` / `text` 字段保持兼容。
23
+ - **恢复 / 迁移基线探针(v0.17.0)**:`doctor --baseline [--against <库路径>] [--template <文件>]` 与 `backup drill <id> --probe [--against <库路径>]` 在目标库 / 恢复副本上跑六类只读探针(身份 / 近期 / 仅源库独有 / CJK / 操作规则 / owner 范围);条目身份键与布局无关,旧平铺 → 新年/月分层的迁移不会误报「缺失」;缺失项列出清单并非零退出(`doctor` exit 2 / `drill` 判失败);探针内容由确定性抽样或用户模板生成,**不硬编码任何记忆**,`--template` 只加严判定。
24
+ - **记忆库安全扫描(v0.17.0)**:`scan` 扫记忆库里的恶意指令 / Prompt 注入 / 凭证泄漏 / 数据外泄 / 护栏绕过 / 行为操纵 / 权限提升七类,五级分级 + `file:line` 证据;默认**只报告**,`--gate` 可接 CI;只有 `--quarantine --yes`(或交互确认)才改写——先把原文件逐字节备份到 `.memory-scan/quarantine/<批次>/` 再替换命中行,`scan --restore` 还原;凭证片段一律打码;规则出处指向元信 / 元钥 / 元安 / 元盾规则表(分工 = 元钥扫源码仓库、元信扫技能包、元忆扫记忆库)。**边界**:`scan` 是库主人的维护命令,会读整库文件(含其它 owner 的私密目录)——智能体不要用它去查看其它智能体的私密内容,跨 owner 扫描前先取得用户授权;加密条目在无授权密钥时不会被解密扫描。
25
+ - **彻底删除 AI 身份(v0.17.0)**:`identity remove <id>` 一次性清掉身份登记、owner 密钥、授权绑定 / 待领取 key / 明文缓存、`private/<id>/` 全部私密记忆(含 owner 索引、profile、distill)、token、grants 引用并重建索引 + 写审计;**公共明文 FACT 保留**,其它 owner 零影响。语义是**真删**(`--dry-run` 先列清单、`--keep-memories` / `--keep-identity` 可部分保留)。**权限边界**:只能由用户本人执行——加密库要主口令(或 `--recovery-key`)、明文库要显式 `--agent user`、`view` 里解锁后的会话等同用户本人;AI 用自身身份调用一律拒绝。破坏性闸门 = doctor + 独立备份 + 事务快照,失败即拒绝执行。
23
26
  - **运行时稳定入口(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`,不写版本目录。
24
27
  - **运行时诊断与握手(v0.16.0 M3)**:`doctor --runtime` 检查 CLI / current / runtime.json / MCP 配置 / 运行中 server / 技能副本 / 身份模式漂移,逐项给出实际版本、期望版本、修复命令和是否阻断;MCP `initialize` / `server/discover` 的 `serverInfo` 返回 `runtimePath` / `identityMode` / `toolProfile`。
25
28
  - **自我学习 / 自我进化 / 自我提升(v0.8.0)**:`recall` 语义检索(同义词 / 拼音 / 字段加权 / 模糊匹配,零依赖);`feedback` 显式使用反馈闭环(useful / useless → weight / confidence / feedback_net 演化,越用越懂);`maintain` 规则层自组织(统一效用分 + 年龄自动归档 / 遗忘候选 / 去重,默认 dry-run,immutable / BOUND 豁免);`distill` 心理日志蒸馏(统计摘要 / 主题画像 / 知识地图,可选 `--model` 外部模型增强);`explain` 查看单条记忆效用分项。
@@ -137,7 +140,9 @@ yotta-memory doctor
137
140
  yotta-memory doctor --json
138
141
  ```
139
142
 
140
- - `doctor` 检查记忆库根目录、加密库密钥文件、公共索引、`agents.json` 与最近备份。
143
+ - `doctor` 检查记忆库根目录、加密库密钥文件、公共索引、`agents.json`、最近备份与**规模**(记忆条数 / 单目录最大文件数 / 索引总体积 / 索引冷启动耗时;只读,不产生写入)。
144
+ - 规模阈值走 `config`:`scale_warn_entries`(默认 50000)/ `scale_warn_files_per_dir`(默认 500)/ `scale_warn_index_bytes`(默认 5242880)/ `scale_warn_cold_start_ms`(默认 2000);超过阈值进 `checks.scale.warnings` 并计入 doctor warning,不锁定破坏性写入。
145
+ - 规模明细在 `doctor --json` 的 `checks.scale`(`entries` / `files_per_dir` / `index_bytes` / `cold_start_ms` / `thresholds` / `level` / `warnings`)。
141
146
  - 严重异常(根目录缺失、密钥库缺文件、备份目录同卷)会返回非零退出码,并锁定破坏性写入。
142
147
  - `maintain --apply`、`consolidate --apply`、`merge`、`archive` 与 `--purge` 在执行前自动创建事务快照;未配置独立备份目录或快照失败时拒绝写入,原记忆保持不变。
143
148
  - 不提供 CLI 跳过快照的开关;`--allow-same-volume` 只用于 `backup create` 的显式临时备份,不会绕过破坏性写入门。
@@ -285,17 +290,17 @@ yotta-memory doctor --json
285
290
  | `yotta-memory reset-password [--password <当前> | --recovery-key <钥匙>] [--new-password <新>]` | 重设主口令(忘口令用恢复钥匙)|
286
291
  | `yotta-memory key list / bind <id> / rotate <id> / claim <id> [--to <AI_HOME> | --agent-key-file <文件>] / status <id> [--to <AI_HOME> | --agent-key-file <文件>] / revoke <id>` | 管理 agent_key binding(**bind/rotate 由用户执行**,需主口令或恢复钥匙;claim/status 由 AI 读取 pending 并落到宿主目录,按同一 AI_HOME 发现规则;revoke 立即吊销该 AI 解密能力,旧 key 随即校验失败;`key list` 合并 `keys/*.key.enc`,显示仅有钥、尚未写记忆的 owner;输出 `[YTM_MIGRATION_REQUIRED]` 时提醒用户走 `view` 重新授权)|
287
292
  | `yotta-memory remember <type> <subject> <statement> [--owner <id>] [--source <来源>] [--weight <0..>] [--verify] [--no-hint]` | 写入(同 subject+statement 自动更新;--owner 标注归属;--source 记录来源;--weight 重要性权重默认 1.0、去重取 max;--verify 写后回读校验;--no-hint 关闭类型启发式提示)|
288
- | `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <command>] [--embedding-timeout N]` | 检索(v0.8.0 默认语义检索:同义词 / 拼音全拼+首字母 / 字段加权 / 模糊匹配 + 效用分融合排序;v0.9.0 支持可选本地 embedding 插件,失败自动降级;`--explain` 显示命中理由与效用分项;`--semantic` 显式开启;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;`--agent <其它>` 只作身份声明/展示,不授予跨读——读他人私密同样要授权;项目级优先)|
293
+ | `yotta-memory recall [关键词] [--type T] [--limit N] [--year <yyyy>] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <command>] [--embedding-timeout N]` | 检索(v0.8.0 默认语义检索:同义词 / 拼音全拼+首字母 / 字段加权 / 模糊匹配 + 效用分融合排序;v0.9.0 支持可选本地 embedding 插件,失败自动降级;v0.17.0 起 `--year` 只检索指定年份,分片索引只读取对应分片、可重复传多次、不传即全量;`--explain` 显示命中理由与效用分项;`--semantic` 显式开启;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;`--agent <其它>` 只作身份声明/展示,不授予跨读——读他人私密同样要授权;项目级优先)|
289
294
  | `yotta-memory profile [--owner <id>]` | 生成用户画像(聚合 `private/<owner>/` 原文,零推断,写 `profile.md`;跨 owner 默认拒绝)|
290
- | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--explain] [--embedding <command>]` | 生成开工上下文包(身份 + 多智能体铁律 + 画像 + 长期摘要 + 任务相关记忆 + 近期走廊 + 近期高价值 + 边界 + 承诺 + 会话闭环契约;--budget 控制动态记忆字符预算,0=不限;--explain 输出 included / dropped 选择 trace)|
295
+ | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--year <yyyy>] [--explain] [--embedding <command>]` | 生成开工上下文包(身份 + 多智能体铁律 + 画像 + 长期摘要 + 任务相关记忆 + 近期走廊 + 近期高价值 + 边界 + 承诺 + 会话闭环契约;--budget 控制动态记忆字符预算,0=不限;v0.17.0 起 `--year` 只装载指定年份,口径同 recall;--explain 输出 included / dropped 选择 trace)|
291
296
  | `yotta-memory forget <文件>` | 移入 `.trash/<时间>/` 回收区并写审计(v0.12.0;不再物理删除)|
292
297
  | `yotta-memory backup volumes / setup --dir <目录> / status / ensure-daily / schedule enable|disable|status` | 每日自动备份(v0.12.0;只展示实际枚举的异卷、用户确认一次位置后默认每日执行,Windows Task Scheduler / systemd timer / launchd 调度,`serve` 补跑)|
293
- | `yotta-memory backup create / list / doctor / restore <ID> --to <目录> / drill [<ID>]` | 备份、恢复与恢复演练(v0.12.0;独立盘校验、SHA-256 清单、排除 `keys/cache`、恢复默认只写新目录;drill 验证 manifest / 索引 / 测试私密解密)|
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` |
298
+ | `yotta-memory backup create / list / doctor / restore <ID> --to <目录> / drill [<ID>] [--probe] [--against <库路径>]` | 备份、恢复与恢复演练(v0.12.0;独立盘校验、SHA-256 清单、排除 `keys/cache`、恢复默认只写新目录;drill 验证 manifest / 索引 / 测试私密解密;v0.17.0 起 `--probe` 在恢复副本上追加六类基线探针,`--against` 校验备份没有落后于源库)|
299
+ | `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>] [--baseline [--against <库路径>] [--template <文件>]]` | 开工可靠性检查(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`;v0.17.0 起 `checks.scale` 给规模体检(条数 / 单目录文件数 / 索引体积 / 冷启动耗时,阈值 `scale_*`),`--baseline` 追加恢复 / 迁移基线探针(结果进 `checks.baseline`,失败 exit 2)|
295
300
  | `yotta-memory archive [--days 180] [--threshold 0.35]` | 归档旧记忆(v0.8.0 统一效用分 + v0.10.0 分类型衰减;immutable / BOUND 豁免;私密归档入 `.archive/private/<owner>/<type>/`;阈值默认读 config `maintain_archived_utility`)|
296
301
  | `yotta-memory reindex` | 重建索引(手动改 .md 后校正)|
297
302
  | `yotta-memory export [--out f.json]` / `import <f.json>` | 导出 / 导入 |
298
- | `yotta-memory config set memory_home <目录>` / `config set backup_dir <目录>` / `config get [--json]` | 持久记住 / 查看记忆库位置与备份目录(`~/.yottamemory/config.json`;`get --json` 同时返回身份状态)|
303
+ | `yotta-memory config set memory_home <目录>` / `config set backup_dir <目录>` / `config get [--json]` | 持久记住 / 查看记忆库位置与备份目录(`~/.yottamemory/config.json`;`get --json` 同时返回身份状态);数值类键含 `maintain_*` / `consolidate_*` / `scale_*` / `backup_max_age_hours` |
299
304
  | `yotta-memory whoami --agent <id> [--agent-key <key>] [--json]` | 查看当前显式身份与登记状态;身份不从环境变量读取;`--json` 返回 `identity` 结构化状态 |
300
305
  | `yotta-memory iam <id> [--name <显示名>] [--user <用户名>] [--relationship <关系>] [--force]` | 登记本智能体唯一身份并自动落自我档案(`agents.json`,ID 必须唯一;可选扩展显示名 / 用户 / 关系)|
301
306
  | `yotta-memory token new --agent <id> [--force]` / `token list` / `token revoke --agent <id>` | 每智能体访问 token:生成 / 列出 / 吊销(登记 `<记忆库>/.server/tokens.json`;同 ID 已被其它来源占用需 `--force` 覆盖,防不同智能体合流)|
@@ -307,6 +312,9 @@ yotta-memory doctor --json
307
312
  | `yotta-memory consolidate [--min-age N] [--min-idle N] [--max-utility N] [--min-group N] [--period N] [--type T] [--model <cmd>] [--apply] [--undo <batch>] [--batches]` | 周期摘要压缩(v0.10.0 压缩遗忘:把超龄 + 长期闲置 + 低效用的同主题旧记忆归纳成**带溯源**的周期摘要并留在活跃区,原文整体进 `.archive/`;默认 dry-run;immutable / BOUND 豁免,活跃 / 高效用记忆不动;`--apply` 执行并写批次审计,`--undo <batch>` 一键回滚(幂等),`--batches` 查近期批次;`--model` 仅本地 CLI)|
308
313
  | `yotta-memory distill [--owner <id>] [--subject <主题>] [--model <cmd>] [--out <路径>]` | 心理日志蒸馏(v0.8.0 自我提升:统计摘要 / 主题画像 / 知识地图;启发式零依赖,`--model` 可选外部模型 stdin→stdout 提炼;私密产物入 `private/<owner>/distills/`,公共入 `facts/distills/`)|
309
314
  | `yotta-memory explain <文件|主题>` | 查看单条记忆效用分项与归档 / 遗忘状态判定(v0.8.0)|
315
+ | `yotta-memory bench [--evalset <文件>] [--k N] [--seed N] [--bootstrap N] [--ablate] [--gate <指标>=<数值>] [--timing] [--year <yyyy>] [--json] [--out <文件>]` | 可复算检索基准评测(v0.17.0:默认按库内条目做确定性抽样生成基线评测集,`--evalset` 可指定评测集 v1;指标 Recall@k / MRR / nDCG@k / HitRate + 固定种子 bootstrap 95% 置信区间;报告带库指纹与评测集指纹、默认不含墙钟时间,同输入必须同输出;`--ablate` 输出关键词 / 语义 × 融合 / 纯分消融;`--gate <指标>=<数值>` 供 CI,不达标 exit 1;`--timing` 显式附带 p50 / p95,带上后报告不再逐字节可复算。**全程只读**:不重建索引、不写访问计数、不调用外部 embedding 插件;索引缺失或过旧时先 `reindex`)|
316
+ | `yotta-memory scan [--path <目录>] [--gate <安全级别>] [--quarantine --yes] [--restore] [--id <批次>] [--json]` | 记忆库安全扫描(v0.17.0:七类 = 恶意指令 / Prompt 注入 / 凭证泄漏 / 数据外泄 / 护栏绕过 / 行为操纵 / 权限提升;五级 `safe → low → medium → high → critical` + `file:line` 证据与规则出处;**默认只报告**、零网络零依赖,`--gate` 命中该级别及以上 exit 1;`--quarantine` 必须先备份到 `.memory-scan/quarantine/` 再替换命中行、需 `--yes` 或交互确认,`--restore` 还原;加密条目无授权密钥时只计入 `summary.encrypted`,`.md.enc` 后缀但内容是平文的文件按文本扫描并计入 `summary.mislabelled`;每条命中给命中片段与命中原文,凭证片段一律打码不回显)|
317
+ | `yotta-memory identity remove <id> [--dry-run] [--yes] [--keep-memories] [--keep-identity] [--password <口令> \| --recovery-key <钥匙>]` | 彻底删除一个 AI 身份与私密记忆(v0.17.0:真删九项 = 身份登记 / owner 密钥 / 授权绑定 / 待领取 key / 明文缓存 / `private/<id>/` 全部私密记忆 / token / grants 引用 / 重建索引 + 审计;**公共明文 FACT 保留**、其它 owner 零影响;只能由用户本人执行——加密库要主口令或恢复钥匙、明文库要显式 `--agent user`、`view` 解锁会话等同用户;破坏性闸门 = doctor + 独立备份 + 事务快照;`--dry-run` 只列清单)|
310
318
 
311
319
  ### 首启(非 TTY / GUI 宿主)
312
320
 
@@ -385,17 +393,19 @@ yotta-memory recall <关键词> --agent <id> --agent-key-file "<AI_HOME>/.yotta-
385
393
 
386
394
  ```
387
395
  <root>/
388
- ├── facts/ # FACT 事实(公共可共享)
389
- ├── private/<owner>/<type>/ # PREF / BOUND / COMMIT,按智能体隔离
396
+ ├── facts/<yyyy>/<mm>/ # FACT 事实(公共可共享),新写入按年/月分层
397
+ ├── private/<owner>/<type>/<yyyy>/<mm>/ # PREF / BOUND / COMMIT,按智能体隔离
390
398
  ├── private/<owner>/profile.md # 用户画像(明文库;加密库为 profile.md.enc)
391
399
  ├── private/<owner>/index.enc # 加密库:每 owner 加密索引(YTMIDX1,Owner Key 加密)
392
- ├── .archive/ # 归档区
400
+ ├── .archive/ # 归档区(保留年/月分层,如 .archive/facts/2026/09/)
393
401
  ├── index.json # 公共 FACT 检索索引(加密库只含公共条目)
394
402
  ├── keys/ # 加密库密钥库:salt / <owner>.key.enc(UMK 包裹) / <owner>.key.recovery(恢复钥匙包裹) / recovery.key.enc / bindings/<id>.key.agent;legacy cache/<id>.key 不再加载
395
403
  └── agents.json # 智能体身份登记表(唯一性)
396
404
  ```
397
405
 
398
- 记忆文件 `<YYYY-MM-DD>-<NNNN>.md`,frontmatter 含 `type / subject / statement / confidence / created / updated / tags / immutable / scope / owner / source / weight / access_count / last_accessed`(`source` 记录来源、`weight` 重要性权重默认 1.0);正文为记忆内容。旧版根下平铺的 `prefs/` `bounds/` `commits/` 会在 `reindex`(或首次 recall 建索引)时按 frontmatter `owner` 自动迁移到 `private/<owner>/<type>/`。
406
+ 记忆文件 `<YYYY-MM-DD>-<NNNN>.md`,frontmatter 含 `type / subject / statement / confidence / created / updated / tags / immutable / scope / owner / source / weight / access_count / last_accessed`(`source` 记录来源、`weight` 重要性权重默认 1.0);正文为记忆内容。**新写入按年/月分层**(如 `facts/2026/09/2026-09-25-0001.md`),读取时新旧路径同时兼容:v0.16 及更早的平铺文件(`facts/*.md`、`private/<owner>/<type>/*.md`)保持原位继续可读,**不做自动迁移**;写入去重也只覆盖当前年/月与平铺根,不会在大库上全量扫描。旧版根下平铺的 `prefs/` `bounds/` `commits/`(更早的布局)仍会在 `reindex`(或首次 recall 建索引)时按 frontmatter `owner` 自动迁移到 `private/<owner>/<type>/`。
407
+
408
+ 归档保留分层:`archive` / `maintain --apply` 把记忆移入 `.archive/` 时按原年/月路径落位(不同月份的同名文件不会互相覆盖),旧平铺文件仍落到归档根。
399
409
 
400
410
  自我档案(本智能体身份,强制落盘):PREF,`subject=自我接入档案`,`owner=<本智能体ID>`,statement 为 `; ` 分隔的 key:value——`agent_id / host / memory_home / mcp_mode(stdio|http)/ engine_url(仅远端)/ token(仅远端;本机不存 token)`,可含 `agent_name / user_name / relationship`(`iam --name/--user/--relationship` 写入)。
401
411
 
package/USER_GUIDE.md CHANGED
@@ -69,6 +69,8 @@
69
69
 
70
70
  > `npx -y @yottameta/yotta-memory` 只是临时运行引擎 CLI,不会安装技能;技能安装器必须使用上面的 `--package ... yotta-memory-install` 形式,或全局安装后的 `yotta-memory-install` 命令。
71
71
 
72
+ > **v0.17.0 升级提示**:升级后请用 0.17.0 引擎执行一次 `yotta-memory reindex`。0.16.7 及更早引擎不识别年/月分层目录,旧引擎重建索引会漏掉分层条目。`doctor` 会报告平铺 / 分层同序号:内容相同的两份只索引一次;内容不同的两份都保留可读并给出路径告警;新写入不复用已占用的序号。
73
+
72
74
  **卸载:** `npm rm -g @yottameta/yotta-memory`,并从智能体的 skills 目录删除整个 `yotta-memory` 文件夹。
73
75
 
74
76
  ## 3. 本机单机使用
@@ -211,7 +213,7 @@ yotta-memory recall <关键词> --agent <id> --agent-key-file "<AI_HOME>/.yotta-
211
213
 
212
214
  - `maintain`(默认 dry-run 预览):列出归档候选与遗忘候选(v0.10.0 起按**分类型衰减后**的效用分 + 年龄判定;默认:utility < 0.35 且超 180 天 = 归档候选,utility < 0.12 且超 365 天 = 遗忘候选)。
213
215
  - **immutable / BOUND 豁免**:红线与边界不参与任何自动归档 / 遗忘。
214
- - `maintain --apply`:执行归档(公共 → `.archive/facts/`,私密 → `.archive/private/<owner>/<type>/`,可恢复)。
216
+ - `maintain --apply`:执行归档(公共 → `.archive/facts/`,私密 → `.archive/private/<owner>/<type>/`,可恢复;年/月分层文件保留原分层,如 `.archive/facts/2025/01/`)。
215
217
  - `maintain --apply --purge`:真删遗忘候选(谨慎;硬删除不可回滚)。
216
218
  - `maintain --dedup`:查重复候选并给**置信度分档**——≥0.85 高置信(可自动合并)/ 0.65–0.85 建议手动 / 其余忽略。
217
219
  - `maintain --dedup --apply`:自动合并同归属(同类型 + 同 scope/owner)高置信组:保留 confidence 最高的一条,合并 tags / 使用次数 / 反馈,其余移入 `.archive/` 并写批次审计(可 `consolidate --undo <batch>` 回滚)。**注意 `--dedup` 与归档互斥**:`--dedup [--apply]` 只查重 / 自动合并,不会顺手归档单条旧记忆——要归档请单独跑 `maintain --apply`。
@@ -266,11 +268,13 @@ yotta-memory recall <关键词> --agent <id> --agent-key-file "<AI_HOME>/.yotta-
266
268
  - `yotta-memory backup volumes` 只列出当前机器实际存在、可写、与记忆库异卷的路径;用户确认一次位置后,`backup setup --dir <目录>` 创建首份备份并默认启用每日自动备份(默认 03:30)。
267
269
  - Windows 使用 Task Scheduler,Linux 使用 systemd user timer(不可用时降级 cron),macOS 使用 LaunchAgent;`serve` 启动后与每 6 小时调用幂等 `backup ensure-daily` 补跑。
268
270
  - `yotta-memory backup status` 查看目录、计划、上次成功、最近失败与调度状态;`backup drill` 恢复到隔离副本,校验 manifest / 索引并解密一条测试私密。
271
+ - `yotta-memory backup drill <id> --probe [--against <库路径>]` 在恢复副本上追加六类只读基线探针(身份 / 近期 / 仅源库独有 / CJK / 操作规则 / owner 范围);`--against` 指向源库时,备份没有落后于源库才算通过,探针失败即演练失败。
269
272
  - 备份目录与记忆库同卷时默认拒绝;这是一条防线,不替代独立盘备份。
270
273
 
271
274
  ## 3.9 开工 doctor 与事务快照(v0.12.2)
272
275
 
273
- - `yotta-memory doctor`:只读检查记忆库根目录、加密库密钥文件、公共索引、`agents.json` 与最近备份;加 `--json` 可输出机器可读结果,顶层含 `schemaVersion` / `encryption` / `migration_required`,并保留 `identity.mode` / `identity.agentKeyStatus`。
276
+ - `yotta-memory doctor`:只读检查记忆库根目录、加密库密钥文件、公共索引、`agents.json`、最近备份与规模(记忆条数 / 单目录最大文件数 / 索引总体积 / 索引冷启动耗时)。规模阈值用 `config set scale_warn_entries 50000`、`scale_warn_files_per_dir`、`scale_warn_index_bytes`、`scale_warn_cold_start_ms` 调整;超阈值只告警,不锁定破坏性写入。加 `--json` 可输出机器可读结果,顶层含 `schemaVersion` / `encryption` / `migration_required`,规模明细在 `checks.scale`,并保留 `identity.mode` / `identity.agentKeyStatus`。
277
+ - `yotta-memory doctor --baseline [--against <库路径>] [--template <文件>]`:恢复 / 迁移后确认记忆真的可用——六类探针(身份 / 近期 / 仅源库独有 / CJK / 操作规则 / owner 范围)全部只读,条目身份键与布局无关(旧平铺 → 新年/月分层不会误报缺失);缺失项列出清单并 exit 2。`--template` 用 v1 JSON 声明显式期望(`expect_owners` / `expect_min_entries` / `expect_types` / `queries`),只加严判定。探针结果在 `doctor --json` 的 `checks.baseline`。
274
278
  - 严重异常(根目录缺失、密钥库缺文件、备份目录同卷)会返回非零退出码;此时 `context` 也会显示“破坏性写入已锁定”。
275
279
  - `maintain --apply`、`consolidate --apply`、`merge`、`archive` 与 `--purge` 在写入前自动创建新的整库事务快照,并在 `.archive/audit-<日期>.jsonl` 记录 transaction / operation / snapshot。
276
280
  - 未配置独立备份目录、doctor critical 或快照失败时,命令直接拒绝执行,原记忆保持不变;`forget` 仍只移入 `.trash/`,不重复创建整库快照。
@@ -344,7 +348,7 @@ yotta-memory token new --agent 我的智能体ID
344
348
 
345
349
  **第 6 步:备份与迁移**
346
350
 
347
- - 备份 = 复制整个记忆目录(`facts/` `private/` `.archive/` + `index.json` + `agents.json` + `.server/`),复制到哪、哪就是记忆库;迁移同理,整个目录拷走即可。
351
+ - 备份 = 复制整个记忆目录(`facts/` `private/` `.archive/` + `index.json` + `agents.json` + `.server/`),其中 `facts/<年>/<月>/` 与 `private/<owner>/<type>/<年>/<月>/` 是分层后的新写入位置;复制到哪、哪就是记忆库,迁移同理,整个目录拷走即可。
348
352
  - `export` / `import` 是把记忆导出成单个 JSON 或从 JSON 导入,适合跨工具交换或归档,不是日常备份的必需步骤。
349
353
 
350
354
  ## 5. 智能体接入篇(本机 / 局域网其它主机)
@@ -433,15 +437,16 @@ yotta-memory key claim <本智能体ID>
433
437
  |---|---|
434
438
  | `yotta-memory init [--project] [--dir <目录>]` | 初始化记忆库 |
435
439
  | `yotta-memory remember <类型> <主题> <内容> [--owner <id>] [--source <来源>] [--weight <0..>] [--verify] [--no-hint]` | 写入记忆(--source 来源;--weight 重要性权重;--verify 写后回读;--no-hint 关闭类型提示)|
436
- | `yotta-memory recall [关键词] [--type T] [--limit N] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <命令>] [--embedding-timeout N]` | 检索记忆(语义 + 效用分排序;可选本地 embedding 插件;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`)|
440
+ | `yotta-memory recall [关键词] [--type T] [--limit N] [--year <yyyy>] [--agent <id>] [--owner <id>] [--all] [--unsafe] [--explain] [--semantic] [--embedding <命令>] [--embedding-timeout N]` | 检索记忆(语义 + 效用分排序;可选本地 embedding 插件;读取分区过滤;越界读其它智能体私密默认拒绝,需 grant / identity=user / `--unsafe`;v0.17.0 起 `--year` 只检索指定年份,分片索引只读对应分片)|
437
441
  | `yotta-memory profile [--owner <id>]` | 生成用户画像(零推断,写 `profile.md`)|
438
- | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--explain] [--embedding <命令>]` | 开工上下文包(身份+铁律+画像+长期摘要+任务相关记忆+近期走廊+近期高价值+边界+承诺+会话闭环契约;--budget 控制动态记忆字符预算;--focus 任务聚焦;--explain 输出 included/dropped 选择解释)|
442
+ | `yotta-memory context [--limit N] [--owner <id>] [--budget N] [--focus <关键词>] [--year <yyyy>] [--explain] [--embedding <命令>]` | 开工上下文包(身份+铁律+画像+长期摘要+任务相关记忆+近期走廊+近期高价值+边界+承诺+会话闭环契约;--budget 控制动态记忆字符预算;--focus 任务聚焦;v0.17.0 起 `--year` 只装载指定年份;--explain 输出 included/dropped 选择解释)|
439
443
  | `yotta-memory forget <文件>` | 删除一条记忆 |
440
- | `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>]` | 开工可靠性检查(v0.12.2:根目录 / 密钥库 / 索引 / 身份 / 最近备份;严重异常时锁定破坏性写入;v0.16.0:`--runtime` 检查 CLI / current / MCP 配置 / 运行中 server / 技能副本漂移)|
441
- | `yotta-memory archive [--days 180] [--threshold 0.4]` | 归档旧记忆(分类型衰减效用分 + 年龄;immutable / BOUND 豁免;私密入 `.archive/private/<owner>/<type>/`)|
444
+ | `yotta-memory doctor [--json] [--runtime] [--mcp-config <文件>] [--skill-dir <目录>] [--baseline [--against <库路径>] [--template <文件>]]` | 开工可靠性检查(v0.12.2:根目录 / 密钥库 / 索引 / 身份 / 最近备份;严重异常时锁定破坏性写入;v0.16.0:`--runtime` 检查 CLI / current / MCP 配置 / 运行中 server / 技能副本漂移;v0.17.0:`checks.scale` 规模体检 + `--baseline` 恢复 / 迁移六类只读探针,失败列出缺失清单并 exit 2)|
445
+ | `yotta-memory archive [--days 180] [--threshold 0.4]` | 归档旧记忆(分类型衰减效用分 + 年龄;immutable / BOUND 豁免;保留年/月分层,私密入 `.archive/private/<owner>/<type>/<年>/<月>/`)|
442
446
  | `yotta-memory reindex` | 重建索引 |
447
+ | `yotta-memory identity remove <id> [--dry-run] [--yes] [--keep-memories] [--keep-identity] [--password <口令> | --recovery-key <钥匙>]` | 彻底删除一个 AI 身份与私密记忆(v0.17.0:真删身份登记 / owner 密钥 / 授权绑定 / 待领取 key / 缓存 / `private/<id>/` / token / grants 并重建索引 + 写审计;公共明文 FACT 保留、其它 AI 零影响;只能由用户本人执行,`view` 里也有「删除」按钮;破坏性闸门 = doctor + 独立备份 + 事务快照)|
443
448
  | `yotta-memory export [--out 文件.json]` / `import <文件.json>` | 导出 / 导入 |
444
- | `yotta-memory config set <键> <值>` / `config get [--json]` | 记忆库位置与引擎参数(`memory_home` / `embedding_cmd` / `embedding_timeout` / `maintain_archived_utility` / `maintain_decay_halflife_<TYPE>` / `consolidate_*` 等;`get --json` 同时返回身份状态)|
449
+ | `yotta-memory config set <键> <值>` / `config get [--json]` | 记忆库位置与引擎参数(`memory_home` / `embedding_cmd` / `embedding_timeout` / `maintain_archived_utility` / `maintain_decay_halflife_<TYPE>` / `consolidate_*` / `scale_*` 等;`get --json` 同时返回身份状态)|
445
450
  | `yotta-memory whoami --agent <id> [--json]` | 查看当前显式身份与登记状态;身份不从环境变量读取;`--json` 返回结构化身份状态 |
446
451
  | `yotta-memory iam <id> [--name <显示名>] [--user <用户名>] [--relationship <关系>] [--force]` | 登记本智能体唯一身份并自动落自我档案(`agents.json`,ID 必须唯一;可选扩展显示名 / 用户 / 关系)|
447
452
  | `yotta-memory token new --agent <id> [--force]` / `token list` / `token revoke --agent <id>` | 访问 token(同 ID 已被其它来源占用需 `--force` 覆盖)|
@@ -453,8 +458,10 @@ yotta-memory key claim <本智能体ID>
453
458
  | `yotta-memory consolidate [--min-age N] [--min-idle N] [--max-utility N] [--min-group N] [--period N] [--type T] [--model <cmd>] [--apply] [--undo <batch>] [--batches]` | 周期摘要压缩(v0.10.0:同主题旧记忆 → 带溯源摘要 + 原文归档;默认 dry-run;`--undo <batch>` 回滚批次;`--batches` 查批次)|
454
459
  | `yotta-memory distill [--owner <id>] [--subject <主题>] [--model <cmd>] [--out <路径>]` | 心理日志蒸馏(v0.8.0:统计摘要 / 主题画像 / 知识地图)|
455
460
  | `yotta-memory explain <文件|主题>` | 查看单条记忆效用分项(v0.8.0)|
461
+ | `yotta-memory bench [--evalset <文件>] [--k N] [--seed N] [--bootstrap N] [--ablate] [--gate <指标>=<数值>] [--timing] [--year <yyyy>] [--json] [--out <文件>]` | 可复算检索基准评测(v0.17.0:默认按库内条目确定性抽样;`--evalset` 指定评测集 v1;指标 Recall@k / MRR / nDCG@k / HitRate + 95% 置信区间;报告含库指纹、默认不含墙钟时间;`--ablate` 消融对比;`--gate` 供 CI;`--timing` 附带耗时后不可逐字节复算;全程只读)|
462
+ | `yotta-memory scan [--path <目录>] [--gate <安全级别>] [--quarantine --yes] [--restore] [--id <批次>] [--json]` | 记忆库安全扫描(v0.17.0:七类 = 恶意指令 / Prompt 注入 / 凭证泄漏 / 数据外泄 / 护栏绕过 / 行为操纵 / 权限提升;五级 + `file:line` 证据;默认只报告、零网络零依赖;`--gate` 命中该级别及以上 exit 1;`--quarantine` 需 `--yes` 或交互确认,先把原文件备份到 `.memory-scan/quarantine/` 再替换命中行;`--restore` 还原;凭证片段打码不回显)|
456
463
 
457
- 类型:`FACT`(事实,共享)/ `PREF`(偏好)/ `BOUND`(边界)/ `COMMIT`(承诺),后三类按智能体物理分目录隔离(`private/<owner>/<type>/`)。
464
+ 类型:`FACT`(事实,共享)/ `PREF`(偏好)/ `BOUND`(边界)/ `COMMIT`(承诺),后三类按智能体物理分目录隔离(`private/<owner>/<type>/`);v0.17.0 起新写入再按年/月分层(`facts/<年>/<月>/`、`private/<owner>/<type>/<年>/<月>/`),旧平铺文件留在原位继续可读,不做自动迁移。
458
465
 
459
466
  ## 7. 故障排查
460
467
 
package/assets/view.html CHANGED
@@ -54,9 +54,10 @@ async function boot(){const s=await api('/api/status');document.getElementById('
54
54
  function showApp(){document.getElementById('lock').style.display='none';document.getElementById('app').style.display='block';loadOwners();load();}
55
55
  async function unlock(){const d=await api('/api/unlock',{password:document.getElementById('pw').value});if(d.error){document.getElementById('lockerr').textContent=d.error;return;}showApp();}
56
56
  async 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;}
57
- 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);}
57
+ 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><button class="danger" data-d="'+esc(o.owner)+'">删除</button>';box.appendChild(c);}
58
58
  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();});};});
59
59
  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();});};});
60
+ box.querySelectorAll('[data-d]').forEach(function(b){b.onclick=function(){var owner=b.getAttribute('data-d');var typed=prompt('彻底删除 '+owner+' 的身份与私密记忆(不可恢复;公共明文保留,其它 AI 不受影响)。请输入完整 ID 确认:');if(typed!==owner)return;b.disabled=true;api('/api/identity-remove',{owner:owner,confirm:typed}).then(function(d){b.disabled=false;if(!d||d.error){alert((d&&d.error)||'删除失败');loadOwners();return;}alert(d.text||'已删除');loadOwners();});};});
60
61
  function 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();}
61
62
  }
62
63
  let off=0,PS=50;