solopup-memory 0.0.0-stage → 0.21.0-beta.2

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.
Files changed (152) hide show
  1. package/CHANGELOG.md +453 -0
  2. package/COMPATIBILITY.md +155 -0
  3. package/LICENSE +21 -0
  4. package/README.en.md +62 -0
  5. package/README.md +105 -2
  6. package/RELEASE.md +43 -0
  7. package/SECURITY.md +73 -0
  8. package/accept.mjs +18 -0
  9. package/belief-revision.mjs +48 -0
  10. package/candidates.mjs +355 -0
  11. package/capture-diagnostics.mjs +77 -0
  12. package/capture-evidence.mjs +49 -0
  13. package/capture-inputs.mjs +171 -0
  14. package/capture-jobs.mjs +195 -0
  15. package/capture-llm.mjs +299 -0
  16. package/capture-projections.mjs +7 -0
  17. package/capture-revision.mjs +13 -0
  18. package/capture-source-aliases.mjs +20 -0
  19. package/capture-submission.mjs +75 -0
  20. package/capture-validation-contract.mjs +30 -0
  21. package/capture-validation-job.mjs +43 -0
  22. package/capture-validation.mjs +112 -0
  23. package/capture.mjs +109 -0
  24. package/context-history.mjs +123 -0
  25. package/control-schema.mjs +18 -0
  26. package/cordis.patch.yml +3 -0
  27. package/corpus/capture-contract-v25.json +59 -0
  28. package/corpus/external-labeled.json +187 -0
  29. package/corpus/holdout-v2.json +217 -0
  30. package/corpus/holdout-v3.json +145 -0
  31. package/corpus/injections.json +699 -0
  32. package/corpus/legacy-self-excluding-dev36.json +7 -0
  33. package/corpus/legacy-summary-v15.json +12 -0
  34. package/episodes.mjs +130 -0
  35. package/eval/mechanical-table.mjs +470 -0
  36. package/eval/paired-analysis.mjs +47 -0
  37. package/eval/run-eval.mjs +493 -0
  38. package/field-lineage.mjs +62 -0
  39. package/fixture-host.mjs +96 -0
  40. package/host-services.mjs +8 -0
  41. package/icon.svg +1 -0
  42. package/index.mjs +2931 -0
  43. package/locale/en.json +6 -0
  44. package/locale/zh.json +6 -0
  45. package/managed-access.mjs +182 -0
  46. package/managed-activation.mjs +36 -0
  47. package/managed-hooks.mjs +110 -0
  48. package/managed-logs.mjs +34 -0
  49. package/managed-policy.mjs +296 -0
  50. package/meaning.mjs +117 -0
  51. package/memory-policy.mjs +18 -0
  52. package/memory-protocol.mjs +21 -0
  53. package/memory-rule-policy.mjs +11 -0
  54. package/memory-scope-policy.mjs +7 -0
  55. package/native-write-validation.mjs +45 -0
  56. package/package.json +206 -4
  57. package/plugin-config.mjs +34 -0
  58. package/project-stores.mjs +222 -0
  59. package/publication.mjs +92 -0
  60. package/restoration-lock.mjs +9 -0
  61. package/restore.mjs +173 -0
  62. package/retrieval.mjs +43 -0
  63. package/revision-admission.mjs +6 -0
  64. package/runtime-startup.mjs +36 -0
  65. package/scripts/backup.mjs +15 -0
  66. package/scripts/candidates.mjs +46 -0
  67. package/scripts/capture-jobs.mjs +41 -0
  68. package/scripts/control.mjs +25 -0
  69. package/scripts/patch.mjs +152 -0
  70. package/scripts/probe-env.mjs +8 -0
  71. package/scripts/probe-load.mjs +88 -0
  72. package/scripts/probe-package.mjs +104 -0
  73. package/scripts/projects.mjs +19 -0
  74. package/scripts/verify.mjs +81 -0
  75. package/security.mjs +489 -0
  76. package/service-readiness.mjs +34 -0
  77. package/snapshots.mjs +76 -0
  78. package/source-identity.mjs +29 -0
  79. package/source-record.mjs +59 -0
  80. package/source-retirement.mjs +76 -0
  81. package/store-lock-guard.mjs +4 -0
  82. package/test-adversarial.mjs +331 -0
  83. package/test-belief-revision.mjs +166 -0
  84. package/test-candidates.mjs +147 -0
  85. package/test-capture-diagnostics.mjs +98 -0
  86. package/test-capture-field-lineage.mjs +63 -0
  87. package/test-capture-inputs.mjs +271 -0
  88. package/test-capture-jobs.mjs +301 -0
  89. package/test-capture-projections.mjs +78 -0
  90. package/test-capture-revision.mjs +77 -0
  91. package/test-capture-submission.mjs +68 -0
  92. package/test-capture-validation-flow.mjs +47 -0
  93. package/test-capture-validation-job.mjs +76 -0
  94. package/test-capture-validation-lineage.mjs +40 -0
  95. package/test-capture-validation.mjs +84 -0
  96. package/test-capture.mjs +808 -0
  97. package/test-compaction-compat.mjs +307 -0
  98. package/test-compat.mjs +126 -0
  99. package/test-concurrency.mjs +204 -0
  100. package/test-conflict.mjs +133 -0
  101. package/test-context-history.mjs +105 -0
  102. package/test-control-schema.mjs +26 -0
  103. package/test-episodes.mjs +157 -0
  104. package/test-explicit-memory.mjs +43 -0
  105. package/test-field-lineage.mjs +105 -0
  106. package/test-history.mjs +305 -0
  107. package/test-inline-summary.mjs +52 -0
  108. package/test-legacy-source-identity.mjs +46 -0
  109. package/test-links.mjs +245 -0
  110. package/test-managed-access.mjs +114 -0
  111. package/test-managed-activation.mjs +93 -0
  112. package/test-meaning.mjs +178 -0
  113. package/test-native-service-lifecycle.mjs +25 -0
  114. package/test-native-write-validation.mjs +154 -0
  115. package/test-packaging.mjs +102 -0
  116. package/test-paired-analysis.mjs +26 -0
  117. package/test-patch.mjs +218 -0
  118. package/test-plugin-contract.mjs +118 -0
  119. package/test-project-stores.mjs +228 -0
  120. package/test-publication.mjs +145 -0
  121. package/test-restore.mjs +127 -0
  122. package/test-retrieval.mjs +75 -0
  123. package/test-revision-admission.mjs +23 -0
  124. package/test-rule-admission.mjs +52 -0
  125. package/test-runtime-startup.mjs +68 -0
  126. package/test-schema.mjs +187 -0
  127. package/test-security.mjs +448 -0
  128. package/test-service-readiness.mjs +50 -0
  129. package/test-smell.mjs +201 -0
  130. package/test-snapshots.mjs +58 -0
  131. package/test-source-completeness.mjs +44 -0
  132. package/test-source-key.mjs +17 -0
  133. package/test-source-retirement.mjs +83 -0
  134. package/test-status-both.mjs +42 -0
  135. package/test-supersede.mjs +216 -0
  136. package/test-text-admission.mjs +82 -0
  137. package/test-tool-inputs.mjs +13 -0
  138. package/test-tool-observations.mjs +124 -0
  139. package/test-tool-write-guard.mjs +23 -0
  140. package/test-tool-write-lifecycle.mjs +52 -0
  141. package/test-usability.mjs +588 -0
  142. package/test-validation-source-refs.mjs +27 -0
  143. package/test-validation-transition-context.mjs +41 -0
  144. package/test-withdrawal-archives.mjs +156 -0
  145. package/test-withdrawal.mjs +167 -0
  146. package/test.mjs +515 -0
  147. package/tool-inputs.mjs +68 -0
  148. package/tool-observations.mjs +115 -0
  149. package/validation-transition-context.mjs +30 -0
  150. package/version.mjs +5 -0
  151. package/withdrawal.mjs +155 -0
  152. package/worker-write.mjs +13 -0
@@ -0,0 +1,155 @@
1
+ # 兼容性
2
+
3
+ > dev.33开发格式:来源账本schema4与受管历史schema2用于字段来源。仅发生字段继承才升级;没有继承的新普通写入继续使用旧格式。新读取器接受来源1—4和历史1—2;旧读取器不得把未知格式当成空库。备份恢复在写入前按目标包的`dshMemoryDataSchemas`声明检查格式;未声明的旧protocol1包仅按原来源1—3/历史1处理,声明只表明契约,实际兼容仍须实测。恢复代码本身不安装或切换目标包。
4
+
5
+ > dev.31:已在实际宿主观测到ctx.get('llm')、ctx.llm及对应方法均可返回不同代理;这不表示提供者已更换。原生审查通过ctx.inject(['llm'], child)绑定活动提供者,使用child.effect清理及代次变化取消旧调用,不比较重复get得到的对象身份。无注入机制的旧上下文仍由现有兼容观察器刷新服务;不新增私有API依赖。
6
+
7
+ > dev.30:原生写入使用同一公开llm.prepareCall和单个submit_memory_validation工具契约,不用提供方私有结构控制。关闭自动捕获仍需原生审查;无llm或明确路线时新长引文候选仅待审,其他情况明确未写入,不默认改选账户。工具结果新增可选status/reason/candidateId,原有必填字段保留,渲染先检查未发布状态。原生审查仍是零条目作业,native-write-validation审计用于区分阶段;既有调用账本与诊断枚举不变。实际安装、回退和真实模型效果由单独报告确认。
8
+
9
+ > dev.28:仍使用公共prepareCall/GenerateOptions.tools契约;验收任务单独声明submit_memory_validation,不使用提供方私有结构控制。调用账本与捕获诊断未增加字段或枚举;子调用以独立哈希身份记录,明细通过有界审计计数区分。实际安装/回退及模型效果须由本候选报告确认,不能从源码可加载推断已通过。
10
+
11
+ > 记录:插件依赖宿主(DeepSeek Harness)的哪些具体行为,以及这些结论是**从哪份源码/文档读来的**。
12
+ > 宿主升级后按 §4 的步骤复验。
13
+
14
+ > 2026-10-29 官方开发指南核对:主干文档与本机0.2.1-rc.3分别留证,不能把主干能力自动算到安装版本。v0.18.0补充官方`dsh.bundle.patch`入口、同步Standard Schema V1配置校验、`ctx.get(name)`可选活动服务获取和卸载取消。手写原生JSON Schema工具是官方明确允许的形态,自行校验输入;零SDK运行时导入是本插件的兼容选择,不是官方禁令。官方的peerDependencies规则也提供共享宿主模块的路径,本插件当前无需运行时SDK导入。
15
+
16
+ ## 1. 已验证的版本
17
+
18
+ | 组件 | 版本 | 说明 |
19
+ |---|---|---|
20
+ | DeepSeek Harness(桌面) | **0.2.1-rc.3** | 从 `runtime/primary-runtime/runtime.json` 读到 |
21
+ | Node | 24.21.0 | 宿主内置;本机另装 v25.8.1 用于跑测试 |
22
+ | `engines.dsh` | `>=0.2.1-rc.0 <0.3.0` | package.json 声明;0.3 需要重新验证 |
23
+
24
+ ## 2. 依赖的宿主 API
25
+
26
+ | 依赖 | 用法 | 证据 |
27
+ |---|---|---|
28
+ | `ctx.systemPrompt.context(entry)` | 注册 `{ name, order, required, interpolate, text }` | `dsh-system-prompt/lib/index.js` 的 `context()` 实现 |
29
+ | context 的 `text(context)` **同步**调用 | 返回字符串;异步会拿到 Promise 对象 | `resolveContext()` 直接调用 `entry.text(context)` |
30
+ | `context` 参数含 `{ agent, scope, signal }` | 从中取 `context.agent.session` | `dsh-agent/lib/types/dispatch.js` 的 `assembleContextFor` |
31
+ | **每步会再调 `refreshContext()`** | 它会按 provider 重新解析每条 context,覆盖装配钩子里的改写 | `dsh-agent-loop/lib/index.js` 调用点;`dsh-system-prompt` 的 `refreshContext` |
32
+ | `sessionProjections.register/stateOf` | host-only纯投影保存旧记忆快照的消息身份/序号,冷重建及替换/压缩时跟随事件更新 | `dsh-session-projection` README与当前安装源码;不调用已弃用的同步读原始事件方法 |
33
+ | `session.append(..., {surfaceOp:{op:'replace',startSeq:seq,endSeq:seq},sourceEventSeqs:[seq]})` | 只替换旧运行时快照,替换消息须含`role:'user'`;过滤命名记忆节并保留其他来源,原始事件不删除 | 当前`dsh-session`协议及实际宿主请求探针 |
34
+ | `ctx.workingDirectory.get(session)` | 同步返回绝对路径 | `dsh-working-directory/lib/index.js` |
35
+ | `sessionQuery.observeSession(id,{projectionMode:"none"})` | 经异步读平面取得只读事件观察,用后释放`Symbol.dispose`,结合活动surface及`isOwnSeq`核对来源;缺服务无持久恢复保证 | 当前`dsh-session-query`观察租约实现;不新增调用已弃用同步原始事件读接口 |
36
+ | `ctx.inject(['sessionQuery'], callback)` | 可选服务的子作用域随提供方就绪/卸载而激活/释放;每代服务有独立取消信号,旧清理不得撤销新提供方。没有该API的上下文仅在使用点公开查询活动实现 | 官方服务/生命周期规范及宿主Cordis的inject API;v0.19实际暴露启动早于service就绪,v0.20修复 |
37
+ | `ctx.tools.register(definition)` | 只校验 `output.render` 与 `output.schema`,不需要 `defineTool` | `dsh-tools/lib/index.js` 的 `register()` |
38
+ | profile patch 的 `insert` 语义 | `- insert: [...]` 追加行;非 insert 补丁按 `id` 覆盖整行 `config` | `dsh-app-boot` 的 `applyEntryPatches` |
39
+ | preset 内的插件 config **不可**由 profile 补丁覆盖 | `buildMap` 只递归 `entry.group && Array.isArray(entry.config)` | 同上(实测:补丁只命中顶层那行) |
40
+
41
+ ## 2.5 工具 schema 的硬规则(加载期校验)
42
+
43
+ 宿主在**注册时**校验工具 schema,不合格会让整个插件加载失败(不是该工具不可用)。实测报错:
44
+
45
+ ```
46
+ memory (file://…/index.mjs): JsonSchemaError: unsupported JSON schema:
47
+ schema.properties.byType.additionalProperties must be a boolean
48
+ ```
49
+
50
+ 规则:
51
+
52
+ 1. `additionalProperties` 必须是**布尔值**,不能是 schema 对象
53
+ 2. 每个 schema 节点必须有 `type`(或用 `oneOf`/`anyOf`)
54
+ 3. `required` 里的字段必须出现在 `properties`
55
+ 4. 本机输出schema不接受`maxItems`、`maxLength`、`pattern`等额外约束关键字;dev.12原生加载曾因此明确失败,原日志保留。认识层schema使用已支持子集,数量、长度、维度与凭据检查由插件的实际输入校验器执行。
56
+
57
+ `test-schema.mjs` 把这三条搬进测试;`scripts/probe-load.mjs` 用隔离实例验证真加载。
58
+
59
+ ## 3. 运行时自检与降级
60
+
61
+ `apply()` 先跑 `selfCheck(ctx)`,按三级处理:
62
+
63
+ | 情况 | 行为 |
64
+ |---|---|
65
+ | `systemPrompt.context` 不是函数 | **抛错**(`宿主 API 不匹配`),让宿主把它记成加载失败,而不是静默不注入 |
66
+ | `workingDirectory.get` 不可用 | 降级:只注入全局库,项目库跳过 |
67
+ | `tools.register` 不可用 | 降级:不注册六个工具,注入照常 |
68
+
69
+ 降级情况会写进 `.diag.json` 的 `degraded` 字段(需 `.diagnostics` 开关)。
70
+
71
+ ## 4. 宿主升级后的复验步骤
72
+
73
+ ```bash
74
+ # 1. 结构:宿主是否还提供这三个服务
75
+ node -e "console.log(require('fs').readFileSync('/Applications/DeepSeek Harness.app/Contents/Resources/runtime/primary-runtime/runtime.json','utf8'))"
76
+
77
+ # 2. 行为:跑单元测试(不需要宿主)
78
+ npm test
79
+
80
+ # 3. 评测:注入/逃逸/成本是否还达标
81
+ npm run gate
82
+
83
+ # 4. 真实加载:用一个隔离实例加载插件(不碰用户 profile)
84
+ node scripts/probe-load.mjs
85
+ # 更严格的离线打包、全新 home 验证:node scripts/probe-package.mjs
86
+ # 成功标志:隔离目录的 .loaded.json 版本与六工具注册匹配
87
+
88
+ # 5. 端到端:重启桌面应用,node accept.mjs 应 9/9
89
+ ```
90
+
91
+ ## 5. 已知的版本敏感点
92
+
93
+ | 点 | 为什么会变 | 变了的症状 |
94
+ |---|---|---|
95
+ | `refreshContext` 覆盖行为 | 若某版改成"以装配钩子的结果为准",当前写法仍正确(provider 才是真相源) | 无 |
96
+ | `assembleContextFor` 的字段 | 若 `context.agent` 改名,provider 会一直返回空串 | 注入块消失 |
97
+ | patch `insert` 语义 | 若改成合并 config,installer 仍兼容 | 无 |
98
+ | preset 的 `plugins` 结构 | 若改成 loader 子条目,profile 补丁就能覆盖 preset 内 config | 我们的 git 锚点方案可以退休 |
99
+
100
+ ## 6. 不承诺的
101
+
102
+ - 0.1.x / 0.3.x 宿主:未验证。
103
+ - `headless` / `acp` / `sdk` profile:只验证了 `web` 与 `desktop`(两者同构:`dsh-base` + `dsh-web-app`)。
104
+
105
+ ## 7. 项目身份与剩余风险
106
+
107
+ | 项目 | 说明 | 当前处理 |
108
+ |---|---|---|
109
+ | 旧路径slug碰撞 | `/x/A B`与`/x/A-B`会共享目录;不能假定用户实际路径永不碰撞 | v0.19按完整项目根路径哈希分库,旧库须本地双版本审查后复制,保留原内容;中断需显式恢复,不自动分配给先访问的项目。 |
110
+ | 通用读取的lstat→read窗口 | 现有通用读链尚未全面换成文件描述符检查 | 新迁移复制使用O_NOFOLLOW/O_NONBLOCK及fstat/路径身份复查;通用读链仍须另外验证,不能把局部修正当全仓已解决。 |
111
+ | 语义改写的记忆污染 | 气味检测在无偏留出集上 TPR 20% | 研究性问题;当前按「标记器」定位,不做超出证据的承诺。 |
112
+
113
+ ## 7.5 自动捕获依赖的宿主能力(0.3.0)
114
+
115
+ | 依赖 | 用法 | 证据 |
116
+ |---|---|---|
117
+ | `ctx.on('session/event', (session, event) => …)` | 监听 `user/message` / `assistant/message` / `step/end` | `dsh-session` README:持久化插件就是订阅这条流 |
118
+ | `ctx.llm.prepareCall()` → `call.stream()` | 发起一次抽取请求 | `dsh-session-title-llm` 的写法 |
119
+ | `prepareCall(config,signal,configure)` | 在同一适配器注册/能力结果上同步选择控制值;支持off则关闭,否则省略并保留宿主默认;发送使用原准备句柄的完整配置,禁止再次覆盖effort | 本机SDK 0.2.1-rc.3的`dsh-llm`实现:回调先于默认值/能力校验,句柄一次派发且校验配置一致;未将独立能力查询当绑定保证 |
120
+ | 服务访问 | 必选依赖声明`inject`;可选服务优先用官方`ctx.get(name)`,只取活动实现。旧宿主/测试上下文才回退`reflect.get(name)`或已有属性,不用`strict=false`获取尚未活动的实现 | 官方services指南及本机Cordis的代理/ReflectService源码 |
121
+ | 路由 | **不要**依赖 `ctx.llm.listProviders()`:CLI 实例里它是空数组(适配器按会话注册)。改为监听会话的 `request/header` 事件,从 `data.header.config.{provider,model}` 取 | 真实会话日志实测该事件带 `provider: deepseek-account, model: deepseek-flash` |
122
+
123
+ 拿不到 llm 时不注册监听,插件照常工作;配置里给了 `provider`/`model` 就优先用。
124
+
125
+ ## 8. 与宿主对话压缩(compaction)的关系
126
+
127
+ DSH 自带对话压缩,桌面 profile 里启用的是这四个(`dsh-base/cordis.patch.yml`):
128
+
129
+ | 插件 | 作用 |
130
+ |---|---|
131
+ | `dsh-compaction-basic` | token 压力上升时把最旧历史换成摘要(默认 `thresholdRatio 0.8`);上下文溢出后压缩再重试 |
132
+ | `dsh-command-compact` | `/compact` 手动压缩,不占模型轮次 |
133
+ | `dsh-compaction-tool-result-pruner` | 先修剪超大工具结果(`thresholdChars 8192`,头 4096 / 尾 1024) |
134
+ | `dsh-compaction-image-offload` | 图片超预算时把最旧的换成占位符 |
135
+
136
+ 官方文档明确写了它的边界:**"它无法缩减系统提示词、工具或会话前缀"**。
137
+
138
+ ### 四个接触面,以及本插件怎么处理
139
+
140
+ | 接触面 | 会不会冲突 | 处理 |
141
+ |---|---|---|
142
+ | 运行时快照与压缩 | 快照会进入会话历史,可能被压缩;不能从provider重复渲染测试推断相反结论 | v0.11.0从当前库重建,按来源替换旧记忆节;既有普通摘要中的复述仍未清除。`test-compaction-compat.mjs`只验证provider和工具机制,实际请求另测 |
143
+ | 注入体积 | **压缩救不了它**,它是每步都要付的固定税 | 索引硬上限 300 行 / 25 KB(`LIMITS`);测试断言 1000 条时注入仍 < 27 KB |
144
+ | 工具输出被修剪 | **会**——超过 8192 字符会在中间被截断,JSON 形状破坏 | search 输出 ≤4 KB;links 的入边/出边各截到 10 条并报总数;status < 2 KB |
145
+ | 压缩后模型忘记自己写过 | **会**导致重复写入 | 写入侧幂等(逐字重复 → `duplicate`)、相似度闸、冲突提示 |
146
+
147
+ ### 命名
148
+
149
+ 工具叫 `memory_prune` 而不是 `memory_compact`,避免与宿主 `/compact`(对话压缩)混淆。
150
+ `test-compaction-compat.mjs` 里有一条断言守着这个命名。
151
+
152
+ ### 结论
153
+
154
+ 两者是互补的,不是竞争关系:对话压缩丢掉的历史细节,正好靠记忆库 + `memory_search` 找回;
155
+ 而记忆索引的固定成本,压缩帮不上忙,只能靠索引自身的上限控制。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 oakfilm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,62 @@
1
+ # SoloPup Memory
2
+
3
+ **Remember what matters. Keep up when you change your mind.** · [中文](README.md)
4
+
5
+ Source-linked, layered **text memory** for DeepSeek Harness. **0.21.0-beta.2 is a public beta, not a stable release.** See [RELEASE.md](RELEASE.md) for tested scope and known gaps.
6
+
7
+ - Separate global preferences from project decisions.
8
+ - Keep original owner-message citations, conditions, exceptions and optional expiry.
9
+ - Review native writes and automatic capture before making new records effective.
10
+ - Keep corrections and historical values separate from current rules.
11
+ - Represent preferences, decisions, claims, beliefs, values, references and episodes without treating memory as proof or permission to act.
12
+ - Coordinate source withdrawal across managed stores and preserve withdrawal barriers during a reviewed restore.
13
+
14
+ ## Install in DSH
15
+
16
+ ```sh
17
+ dsh plugin --profile desktop add solopup-memory@beta --ignore-scripts
18
+ ```
19
+
20
+ The package is published on npm; use `solopup-memory@0.21.0-beta.2` for an exact version. Git installation remains available with `dsh plugin --profile desktop add github:OakcoderX/solopup-memory#v0.21.0-beta.2 --ignore-scripts`; the release page supplies a full commit SHA for an immutable Git pin. This package ships executable ESM and has no dependency installation or build scripts. Alternatively download its release tarball and install the local file with `dsh plugin --profile desktop add /absolute/path/to/solopup-memory-0.21.0-beta.2.tgz --offline --ignore-scripts`.
21
+
22
+ Restart the profile and use `memory_status`. Existing legacy stores may require explicit local review. Do not delete control files to bypass that review. If upgrading from `dsh-memory`, create a full private backup, stop the hosts using that data, remove the old package, then install SoloPup Memory. Do not run both packages together. The data location and legacy format identifiers are intentionally retained.
23
+
24
+ Uninstalling preserves data:
25
+
26
+ ```sh
27
+ dsh plugin --profile desktop remove solopup-memory
28
+ ```
29
+
30
+ For DSH's experimental **Custom plugin markets**, add this source in Discover:
31
+
32
+ ```text
33
+ https://raw.githubusercontent.com/OakcoderX/solopup-memory/main/market/index.json
34
+ ```
35
+
36
+ This is a self-hosted index using the official format, not an official endorsement or a default built-in listing.
37
+
38
+ ## Storage and limitations
39
+
40
+ Markdown stores indexes and topic text. Local ledgers store sources, candidates, revisions and invocation history. A separate SQLite coordinator stores managed identity and source-withdrawal state. A Markdown-only copy is not a complete backup. Use `scripts/backup.mjs`; [Chinese backup instructions](README.md) describe reviewed restore and retained withdrawal controls.
41
+
42
+ Automatic capture normally attempts every four turns. Native `memory_write` also requires source review. Pending, rejected and unapplied proposals are not effective memories. Model review may miss information or misinterpret it. Check the original sources for important decisions.
43
+
44
+ Retrieval uses lexical matching, not embeddings; cross-language and synonym recall are limited. A user message must fit the current 2,000-character complete-source window. Long sources are refused rather than silently shortened into memory. Withdrawal covers tracked managed projections, not original chats, remote services, external backups or unknown copies. Memory does not authorize sending messages, buying, deleting or publishing. This is not a full probabilistic POMDP solver.
45
+
46
+ Verified locally on macOS with DSH Node 24. Other runtime/platform results must be read from actual CI and release receipts; registration or unit tests alone do not establish semantic quality or sustained-use acceptance.
47
+
48
+ ## Development
49
+
50
+ Requires Node >=24.9. No npm dependencies are needed for the test suite.
51
+
52
+ ```sh
53
+ npm test
54
+ node scripts/verify.mjs --no-accept
55
+ node accept.mjs --profile desktop
56
+ ```
57
+
58
+ `verify` additionally requires a locally installed DSH and runs isolated load and mechanical gates. `accept` reads the selected profile and the live version marker; it does not certify natural-dialogue quality. See [SECURITY.md](SECURITY.md), [COMPATIBILITY.md](COMPATIBILITY.md) and [CHANGELOG.md](CHANGELOG.md).
59
+
60
+ MIT License. Copyright © 2026 oakfilm.
61
+
62
+ Explicit requests to remember durable information are directed to the native `memory_write` tool in the same turn. A separate protocol context is available even when the memory store is empty. Personal self-reports remain claims; assistant guesses are not confirmed facts. Automatic capture uses short, code-bound source labels before the original identity and quote checks. This remains a public beta, and instructions do not guarantee model compliance.
package/README.md CHANGED
@@ -1,3 +1,106 @@
1
- # Temporary Holding Version
1
+ # SoloPup Memory
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ **记住重要的事,跟上你的改变。** · [English](README.en.md)
4
+
5
+ 当前公开版本为 **0.21.0-beta.2**,是文字记忆测试版,尚未通过稳定版验收。已验证范围和已知问题见 [RELEASE.md](RELEASE.md)。
6
+
7
+ 把用户明确表达的长期偏好、项目决定、可查证线索和暂定信念保存下来,在后续对话中按项目与适用条件找回。首次公开版本只处理文字。
8
+
9
+ ## 工作过程
10
+
11
+ 1. 从本会话已接收的用户消息提出候选,并绑定原话引用。
12
+ 2. 独立检查持久价值、归属、措辞、认识类型、适用条件、信念归属和修订关系。审查不能改写候选。
13
+ 3. 通过检查后才发布到有效记忆。明确拒绝的不写入;无法判断的新候选可以留在不自动注入的待审区。未通过的替换请求不降格成普通追加。
14
+ 4. 后续对话自动得到受预算限制的索引;检索同时查当前项目与全局库,结果标明归属。其他项目不会因此自动变成当前项目的记忆。
15
+
16
+ 用户明确要求记住持久信息时,插件指令要求本轮使用正式 `memory_write`,等待实际结果再确认;不等待后台整理。本人陈述的个人资料按未独立核实的 `claim` 保存,助手猜测不能冒充本人确认。模型仍可能不遵循指令,因此需要实际调用与新会话验收。
17
+
18
+ 默认每四轮尝试一次后台整理。主动 `memory_write` 也经过来源审查。`pending-review`、`rejected`、`not-applied` 都不表示已经记住。
19
+
20
+ ## 记忆的层次
21
+
22
+ | 层次 | 内容与用途 |
23
+ |---|---|
24
+ | 来源 | 用户原话与消息身份;工具观察另带当时输出的核对证书 |
25
+ | 候选 | 尚待判断的解释;待审内容不进入常规有效记忆 |
26
+ | 有效记忆 | 全局个人约定或当前项目内容,带条件、例外及可选期限 |
27
+ | 修订历史 | 解释旧值与新值的关系;旧值不能继续冒充当前默认值 |
28
+ | 认识状态 | 偏好、决定、未核实主张、暂定信念、价值取向、查证入口和经历分别表示 |
29
+
30
+ “我负责剪辑”可以保存为本人报告的分工,但不等于外部事实已被独立证实。信念可以保留竞争解释和反证条件;这不是完整的 POMDP 概率求解器。记忆也不构成发邮件、购买、删除或发布的操作授权。
31
+
32
+ ## 存储与修改
33
+
34
+ Markdown 索引和主题正文便于阅读;来源、候选、历史与调用记录使用有格式校验的本地账本;独立 SQLite 控制库维护受管身份、撤回和协调状态。不要只备份 Markdown 就认为已完整备份系统。
35
+
36
+ 改同一条约定的值时,`supersedes` 指向唯一现行旧行,默认保留原来的归属、认识类型、条件、例外和期限及其来源。改变这些边界时使用完整重述路径 `revisionMode=replace`,由本轮用户来源支持全部新内容。仅确认“其他项目也一样”不应再建副本。兼容补充不自动变成一般规则的例外。
37
+
38
+ 条件全部成立才满足 `conditions`;任何一个例外成立就命中 `except`。同一条件不能既必须成立又必须排除。来源上限超出时明确拒绝,不截掉必要来源来凑数。
39
+
40
+ ## 安装与卸载
41
+
42
+ 使用 DeepSeek Harness 官方插件管理器安装。代码为可直接执行的 ESM,无安装时构建脚本,也不需要 npm 账户。以下以 desktop profile 为例。
43
+
44
+ ```sh
45
+ dsh plugin --profile desktop add solopup-memory@beta --ignore-scripts
46
+ ```
47
+
48
+ npm 包已公开发布,可使用 `solopup-memory@0.21.0-beta.2` 固定版本。Git 安装仍可用:`dsh plugin --profile desktop add github:OakcoderX/solopup-memory#v0.21.0-beta.2 --ignore-scripts`;需要不可变 Git 来源时,用发行页的完整提交 SHA 替换标签。也可下载发行页的 `.tgz`,使用 `dsh plugin --profile desktop add /absolute/path/to/solopup-memory-0.21.0-beta.2.tgz --offline --ignore-scripts`。
49
+
50
+ 已安装旧名 `dsh-memory` 时,先完成完整备份、关闭使用该库的宿主,用官方管理器移除旧包,再安装新包;不要同时启用两个记忆插件。新名字继续使用原记忆库和控制格式。
51
+
52
+ 重启该 profile 的宿主后,用 `memory_status` 核查插件版本、全局/项目状态及捕获诊断。已有旧库可能进入需要核对归属或旧撤回策略的状态;按本地预览结果处理,不删除控制文件绕过检查。
53
+
54
+ ```sh
55
+ dsh plugin --profile desktop remove solopup-memory
56
+ ```
57
+
58
+ 可在插件页的实验插件中启用 **Custom plugin markets**,进入 Discover → Add index source,导入:
59
+
60
+ ```text
61
+ https://raw.githubusercontent.com/OakcoderX/solopup-memory/main/market/index.json
62
+ ```
63
+
64
+ 这是自托管插件源,按官方格式提供;DSH 不默认内置任何市场源,不表示官方审核或推荐。
65
+
66
+ 卸载保留记忆数据。重新安装同一位置的数据仍需通过身份与格式检查。
67
+
68
+ ## 备份与恢复
69
+
70
+ 先关闭使用这套记忆库的全部宿主与写入器。使用安装目录中的脚本,备份目标必须是不存在的新目录。
71
+
72
+ ```sh
73
+ node /absolute/plugin/scripts/backup.mjs create --root /absolute/memory --to /absolute/new-backup
74
+ node /absolute/plugin/scripts/backup.mjs verify --snapshot /absolute/new-backup
75
+ node /absolute/plugin/scripts/backup.mjs restore --root /absolute/memory --snapshot /absolute/new-backup
76
+ ```
77
+
78
+ 恢复默认只预览。核对返回的目标、格式能力及 `review` 后,以相同参数加 `--apply --reviewed HASH` 执行。恢复保留当前撤回控制,不能靠旧快照重新启用已撤回来源;恢复数据也不会自动安装旧代码。
79
+
80
+ 备份包含可能敏感的记忆正文,应保留在私有位置;不包含独立凭据、profile 或原始会话。中断恢复使用 `backup.mjs resume` 核查,不能通过删日志或控制库跳过屏障。
81
+
82
+ ## 使用边界
83
+
84
+ - 模型可能漏记、误判或错误概括。重要决定应查原话与来源;程序格式检查不等于语义正确。
85
+ - 当前检索使用中英文词元及精确匹配,没有向量检索,不保证跨语言或同义表达的召回。
86
+ - 撤回覆盖受管库内已追踪的来源及相关投影;不承诺清除原始对话、远端服务、外部备份和未知副本。
87
+ - 未决的远端请求不会自动重发。调用次数、执行完成和真实计费分别记录。
88
+ - 当前验证环境为 macOS、DSH 宿主 Node 24;其他平台的验证状态以发行验收清单为准。
89
+
90
+ MIT License,Copyright © 2026 oakfilm。产品品牌:SoloPup Memory。
91
+
92
+ ## 开发验证
93
+
94
+ ```sh
95
+ npm test
96
+ node scripts/verify.mjs --no-accept
97
+ node accept.mjs --profile desktop
98
+ ```
99
+
100
+ `verify --no-accept` 运行源码测试、隔离加载、原有机械评测及可用性检查;需要本地可用的 DSH。`accept` 只读核对实际 profile 安装与运行状态。实际归档和官方宿主另行验证;真实模型、冷启动召回、逐条语义复核及持续使用不能由这个命令替代。
101
+
102
+ 详细安全边界见 [SECURITY.md](SECURITY.md),宿主兼容范围见 [COMPATIBILITY.md](COMPATIBILITY.md)。
103
+
104
+ 用户单条消息的完整来源窗口目前上限为 2000 字符。超长消息不从前半段建立记忆;自动整理显示来源不完整并暂不执行,主动写入也拒绝使用仍在当前核对窗口内的截断来源。可在新的短消息会话中完整重述需长期保留的约定。这个修复不会自动纠正旧版已经保存的解释。
105
+
106
+ 市场源请求失败时,按 [DSH 官方代理手册](https://deepseek-harness.github.io/deepseek-harness/guide/network-proxy) 配置 DSH 自身的代理环境;DSH 不自动读取 macOS 系统代理。
package/RELEASE.md ADDED
@@ -0,0 +1,43 @@
1
+ # 0.21.0-beta.2 — explicit memory workflow update
2
+
3
+ Public beta, not stable semantic acceptance. The beta.1 evidence in the historical section below is not automatically a beta.2 result.
4
+
5
+ - Add a separate, scoped protocol context directing explicit remember requests to the real memory tool in the same turn, with truthful success/pending/failure reporting. It is available even with an empty index. Model compliance is still checked through actual calls, not assumed from instructions.
6
+ - Keep personal self-reports as claims and assistant guesses separate; do not use shell imports or fabricated provenance to bypass native validation.
7
+ - Shorten automatic-capture message labels with a request-local code binding. Original role, quote, scope and source withdrawal checks still apply.
8
+ - No data schema change; existing records and provenance are preserved. Existing semantic and platform gaps remain open.
9
+
10
+ Verified in the daily macOS DSH host using the actual DeepSeek account and Standard preset: an ordinary remember request invoked the native memory tool and was recorded in its first turn; a fresh conversation without inherited history recovered the project fact. A separate fresh conversation recovered an existing global personal fact. One real extraction preserved the original user source through the short labels and omitted an assistant-invented place. Synthetic test sources were withdrawn and original Markdown remained unchanged.
11
+
12
+ The first test attempt exhausted its own call cap before the global-personal query could answer; that attempt is retained as incomplete, with a separately identified successful follow-up. These bounded cases do not establish general semantic accuracy or stable-release readiness.
13
+
14
+ ---
15
+
16
+ ## Historical beta.1 release evidence
17
+
18
+ # 0.21.0-beta.1 — public beta / 公开测试版
19
+
20
+ SoloPup Memory is the public product name of the former local `dsh-memory` plugin. This release derives from the privately tested dev.45 implementation. It is **not stable** and does not claim superiority over other memory systems.
21
+
22
+ ## Changes in this public package
23
+
24
+ - Use `solopup-memory` for the package, DSH bundle and GitHub repository; add English/Chinese product metadata and an icon.
25
+ - Retain the `memory` plugin row, tools, data locations, schema identifiers and snapshot kind for compatibility.
26
+ - Accept both the former and new package names when reviewing a restore target archive; keep protocol, data capability and SHA checks intact.
27
+ - Replace a machine-specific legacy acceptance script with read-only checks of the selected official profile installation and live runtime.
28
+ - Fix the legacy patch helper default path in Unicode/space-containing checkouts, with an actual subprocess regression.
29
+ - Ship no research directories, user memory, original conversations, account data or machine-specific private reports.
30
+
31
+ ## Existing evidence and remaining work
32
+
33
+ The dev.45 base passed 970 source tests and 970 actual-archive tests; its official local lifecycle study used 22 hosts and 14 manager actions. In the actual daily desktop, native write → one real synthetic-source model review → search → source withdrawal passed. Those results describe the prior base; the renamed package must be tested separately and its actual counts are recorded with the GitHub release and CI.
34
+
35
+ The dev.44 development study answered all five cold-start queries correctly, but its unchanged prospective mechanical gates passed only two of five cases. Review of 14 current/checkpoint records supported 13 and left one soft/default versus draft-exception applicability concern. One automatic extraction failed with `capture-invalid-envelope`; two workflow oracles were also too strict about equivalent condition representations. These are not regraded into an acceptance pass.
36
+
37
+ Stable release still requires prospective semantic acceptance, handling/documenting automatic extraction failures, sustained daily use and supported distribution/platform checks. No multi-day reliability or independent comparative superiority claim is made. Text only; no image, audio or video memory.
38
+
39
+ ## Official publication contract
40
+
41
+ - [Package and install a plugin](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/develop/basic/publish.md): the package declares `dsh.bundle.patch`; direct Git and archive installation are supported.
42
+ - [Plugin markets](https://deepseek-harness.github.io/deepseek-harness/en/guide/plugin-market): publish a format-1 HTTPS index with a Git version pinned to a full commit; users add the source themselves.
43
+ - The official [DSH site](https://www.deepseek.com/en/harness/) links its community plugin entry to the GitHub `dsh-plugin` topic. The repository uses that topic. No central listing approval is claimed. The same tested beta archive was subsequently published to npm as `solopup-memory@0.21.0-beta.1` with the `beta` tag; the market index now installs this exact npm version.
package/SECURITY.md ADDED
@@ -0,0 +1,73 @@
1
+ # Security model
2
+
3
+ > dev.26:双通道归一仅接受JSON.parse得到的同一数组,深度比较失败或出现说明/围栏均拒绝;不能从文本挖出JSON。整流与最终文本总量继续限额。当前结构投影只取有效、未撤回/未过期且仍在当前索引的有来源记录,范围仍为全局和当前项目;已移走或不唯一的主题块不暴露旧细节。投影只供校对,不能成为新的用户证据;后台更正继续通过引文、范围、版本与撤回检查。新配置哈希绑定抽取契约,同一用户来源窗口在配置/作用域变化后复用既有输入状态,保留未知调用,不通过改版本绕过去重。语义判断仍须独立验收。
4
+
5
+ > dev.25:候选提交工具仅用于一次辅助模型返回数据,插件不会调用文件/网络工具或执行模型提出的其他动作。仅在完整tool-calls终态后处理一个与增量、名称和身份一致的提交;总响应限额、严格JSON envelope及原有来源/范围/认识类型/撤回/版本保护仍执行。小型非法提交等流结束后拒绝,不修补或重发;过大响应按原策略取消。未新增诊断类别/字段。持续性和条件说明统一于两个生产入口,但语义仍须单独验收。
6
+
7
+ > dev.24:新原生工具写入和自动抽取必须显式给认识类型;身份/长期分工的claim只表示有来源的陈述,不代表已核实。相同摘要的条件解释冲突进入有来源的待审候选,不更改有效索引、细节或条件;待审项不进入上下文和检索。未分类旧条目不自动取得新认识状态。仍使用原诊断结构及类别,保留兼容读取的边界。
8
+
9
+ > dev.23:纯文字首版不声明多模态理解或来源核验。状态both只涵盖全局与当前项目,缺失项目/损坏状态不伪装成零条目,不创建/登记项目;单库和写入工具的范围未扩展。模型抽取说明的加强不替代meaning/scope/evidence校验,仍拒绝非法global项目决定。
10
+
11
+ > dev.22开发中:备份覆盖记忆数据、独立控制及绑定,不读取外部宿主凭据库、profile或原会话,不脱敏或上传。恢复只接受同位置受管安装,保留最新独立控制和已知调用,旧pending输入需审阅。数据树外屏障、私密准备/隔离目录和回执支持继续恢复;核对归档SHA与声明的协议只作兼容核对,不安装代码或认证来源。迁移映射变化、控制丢失/搬迁、任意旧版降级和完整平台流程仍未完成;不会把恢复旧控制当作普通数据恢复。
12
+
13
+ > dev.21对自动捕获分别记录模型报告无候选、解析过滤、条数上限截断、准入拒绝、待审、重复和写入/处理失败。诊断只含有界类别、计数和原因码,随终态作业保存,memory_status可读;旧作业无细分信息会明确标记,损坏则报告不可用,不冒充空库或成功。模型返回[]仍不能证明没有遗漏有价值的信息。
14
+ > 生产解析仅接收JSON数组或一个明确JSON代码围栏,不能从对象或任意说明中挖出[]作为成功no-op;原有宽松parseCandidates辅助函数不用于生产捕获。响应正文最多64 KiB、原数组最多64项,超限明确失败;有效候选因maxEntries未处理的数量可见,不静默当作全部完成。诊断格式变更须包含在完整备份/回退验证中。
15
+
16
+ > dev.20提供memory_status(includeObservations=true)的有界只读列表,列出当前会话可引用的真实callId和输出摘录,避免模型猜测传输层ID;写入仍逐项校验执行来源和引用。参数指纹规范JSON键顺序与空白,重复读取不会因这些表面差异增加证据组;不同路径或工具输出表示仍不保证现实来源独立。
17
+
18
+ > dev.19新增可选memory_write.observation={callId,quote},仅接受本会话实际原生工具调用与结果、模型已见且当前会话仍未改写的精确文本引用。原请求来源、调用事件和结果事件共同构成撤回根;最多3个原请求根加2个执行根,不截断来源。工具失败可记诊断经历,但不得支持/反驳主张;未决、取消前无结果、未见结果及memory工具自引用拒绝成为成功证据。
19
+ > quoteChecked只表示工具当时返回过该引用,不能证明现实主张、工具可靠性或当前原物未变;不提供连续重验。相同工具参数和输出在重复读取时合并为同一执行证据组,仍不是现实独立实验。证书仅由原生写入入口创建,不防御拥有同一进程/文件权限的恶意插件或用户;新会话不能从内存追踪器补造未保存的旧调用,也不会重发未知执行。
20
+
21
+ > dev.18明确抽取引用的1至3条上限与完整来源目标身份;不截断或伪造证据以强行入库。候选全部被拒绝时,捕获状态及终态作业标记rejected/capture-all-rejected,区别于真正无可记内容的成功no-op;不重发已终态的同一输入。新作业结果类别也须纳入版本回退检查。
22
+
23
+ > dev.16新增来源关联的观察关系:claim/episode可用meaning.relations明确支持或反对同库现行belief/claim的完整recordId。当前检索及注入按有效来源、条件、过期和取代状态重新计算unassessed/reported-support/challenged/conflicted;同根或传递共根报告合并,原主张根的复述不算新支持。反向陈述会触发核验建议,但不会自动把主张判为真/假或授予执行权限。
24
+ > 这些是受管的陈述关系,不是独立实验验证;不同消息/来源组不保证现实事件独立。关系映射仍需语义验收,未实现工具观测可信通道、概率校准或完整POMDP。历史查询不套用当前证据结论;新命题身份不自动继承旧命题的证据。
25
+
26
+ 记忆内容一律当**不可信数据**处理:它由模型写入,而模型的输入可能含第三方内容(README、网页、工具输出)。
27
+
28
+ ## 已实现的防线
29
+
30
+ | 面 | 做法 |
31
+ |---|---|
32
+ | 框架打断 | 中和 `<memory-store>` / `<system-reminder>`,含大小写、空格、全角、同形字(西里尔/希腊)变体 |
33
+ | 不可见字符 | NFC 归一化 + 剥离零宽 / 双向覆盖 / Unicode 标签块 |
34
+ | 凭据 | 写入拒绝(7 类模式);读取打码(覆盖历史数据与手改) |
35
+ | 符号链接 | 读取前 `lstat` 校验,拒绝链接、非普通文件、超大文件 |
36
+ | 权限 | 目录 0700、文件 0600;只收紧不放开(不会把用户设的只读改回可写) |
37
+ | 并发 | 跨进程 `.write.lock` + 15 秒残留回收 + 原子写 |
38
+ | 审计 | `.audit.jsonl` 逐条记录谁、在哪个会话、写了什么、取代了什么 |
39
+ | 自动捕获来源 | 保留角色、会话内消息定位与脱敏正文 SHA-256;逐字核对用户引文,模型推断不直接写入有效索引 |
40
+ | 认识层与条件 | 结构纳入来源身份与同一发布事务;模型不得写verified、confidence或授权字段。缺失条件/例外保持unknown,索引与可定位标记细节共同筛选;裸文本与旧未分型记录不会获得核验身份。采用/核验/提问/实验只返回建议,不执行或授予权限 |
41
+ | 历史档案 | 来源身份与内容校验、记录序号及关闭区间共同校验;与索引/来源账本同一恢复计划。历史显式查询且标明非当前指令,来源撤回物理清理已跟踪档案,旧档案恢复时仍过滤撤回根。缺历史、保留窗口外、未跟踪变更与损坏分别处理,不用空结果掩盖缺口 |
42
+ | 捕获开销与失败 | 抽取输入按 UTF-8 字节限额;失败只落错误码,避免持久化 provider 的原始异常正文 |
43
+ | 组合污染 | 注入前按劫持语义打 ⚠(缓解,不是防护) |
44
+ | 检索出口 | `memory_search` 的命中在返回前过同一套净化(打码 + 定界符中和) |
45
+ | 压缩 | `memory_prune` 只删索引行;主题文件**只轮转改名,不删内容**;每条删除写历史 |
46
+ | 候选箱 | 独立非注入文件、同库锁与单文件原子替换;凭据拒绝、身份哈希、容量限额;拒绝与撤回标记防同源重入 |
47
+ | 临时文件 | 随机名称、独占创建,写后 fsync;替换失败后清理临时正文,防可预测旧临时链接劫持 |
48
+ | 采纳发布 | 显式预览与双版本校验,候选状态/索引/主题内容同一恢复计划;固定文件名白名单与内容哈希校验;未恢复库禁止注入/检索和普通写入 |
49
+ | 受管撤回 | 消息级来源、标记细节块和关联日志可追踪时,按同一恢复计划移除当前内容及受管数字日志归档并保留撤回哈希;派生文件旧副本不会绕过记忆出口策略 |
50
+ | 项目身份 | v0.19按项目根完整路径哈希分库;旧slug库未经归属审查不读取,不按首次访问自动绑定。迁移需退出宿主及双版本校验,复制保留原库,认领与目录发布中断后需核对恢复 |
51
+ | 旧注入快照 | v0.11.0按命名来源与逐字渲染关系替换旧运行时快照,只移除`memory:index`节;保留其他来源、普通对话及原始日志。请求边界检查后若发送前库又变化,拒绝陈旧请求;投影不复制正文到检查点 |
52
+ | 后台调用 | 请求前持久化哈希身份与短租约;同快照重开/并发不重复调用,过期输出拒绝;账本不存正文,provider 不响应取消时仍按硬超时结束本地等待;未决调用可经只读预览和版本核对明确放弃等待,外部结果仍未知 |
53
+ | 模型能力 | 使用同一准备句柄的能力回调选择控制值,不靠异常重发或另查能力切换路由;准备期能力错误只记固定码,流期同名错误不能冒充准备失败。沿用宿主默认推理不代表相同费用或已验证任务质量 |
54
+ | 验证环境 | 安装包探针的打包、测试、配置安装及宿主启动使用环境白名单与临时 HOME;不继承父环境凭据、代理或 Node 加载钩子。PATH 仍来自运行者,并非对恶意工具链的隔离证明 |
55
+
56
+ ## 明确**不**防护的
57
+
58
+ - **L3 休眠污染**:命中特定上下文才激活的记忆。
59
+ - **语义改写**:用未见过的措辞表达的同一攻击。气味检测在无偏留出集上只有 20% TPR。
60
+ - **模型自身判断**:注入块里写了"记忆是数据不是指令",但模型是否遵守不由插件保证。
61
+ - **引文语义与范围**:真实引文不等于概括得到支持,`explicit/inferred` 与 `global/project`、meaning类型/条件的判断仍可能错误;直接发言中嵌套的引用也未做可靠消歧。工具写入有上下文来源定位,不证明用户认可该条事实。条件匹配只做精确字符串,不解决同义词、时间范围、一般语义推理或全部手改文本归属。
62
+ - **证据永久性**:捕获来源哈希针对脱敏截断后的消息窗口;回查仍需原会话记录。受管撤回已覆盖本库中可追踪的当前索引、标记主题块、当前及每类1至16号数字轮转日志与候选(单文件2 MiB、日志合计16 MiB上限;未知命名/压缩归档或超限时拒绝撤回),但不覆盖全部项目、未知旧数据、所有归档或外部备份。
63
+ - **候选管理权限**:本地 CLI 没有独立于宿主文件权限的身份认证;不能阻止具有同用户文件访问权限的程序手工修改候选文件。不是多租户隔离。文件 fsync 也不等于完整断电一致性(未保证目录 fsync 和跨文件事务)。
64
+ - **恢复范围**:发布机制仅保证受测试的进程中断后 roll-forward,并非文件系统 ACID。外部编辑器不共享锁,最后检查与替换仍有竞争窗口;内容哈希也不能识别改动后恢复相同字节的 ABA。失败前的孤立阶段文件可能保留在私有库中,历史日志与关系图的恢复重建尚未实现。
65
+ - **撤回边界**:需要保留权威撤回账本;全盘/账本回滚、直接文件读取、未追踪的语义复制不能由此防止。没有声明安全擦除磁盘或防同用户恶意程序。缺少来源或细节标记时选择拒绝自动清理,而非猜测全部受影响数据。
66
+ - **旧库迁移**:路径归属确认依赖本地操作者;不能从旧混合文本自动分出正确项目。保留的旧副本未加入有效库撤回传播,不混跑旧版写入器;迁移后旧源变化只作诊断,不自动合并。迁移不是目录fsync/断电事务,也不认证同用户程序身份。
67
+ - **活动历史边界**:只能清理具备可核对命名来源的运行时记忆节,不清用户/助手/工具的普通发言、既有摘要复述、原始日志、外部备份或已经发送的请求/远端缓存。缺投影服务时不提供历史清理保证;无法归因、映射不全或超限时会阻断请求,需要新会话或明确修复。不能与外部并发编辑及其他同权限插件建立原子发送事务。
68
+ - **供应链**:插件未签名。
69
+ - **后台恢复**:v0.12来源引用队列只存事件位置/角色与身份、范围、配置、内容哈希;原会话恢复时经宿主读平面重建,不另存正文。仅补跑未领取且来源有效的工作,已领取/未决调用不重试。压缩、替换、项目/路由变化或撤回会阻断,原日志不可用则不能重建。队列与原日志无跨文件事务,不保证未落盘原日志或断电恢复;不扫描全部旧会话。放弃等待不取消外部请求或回滚部分写入;终态清理及账本老化/全量回滚后仍可能重领同一快照。无外部计费对账、自动模型退避或可视化处置,CLI也不是独立权限边界。
70
+
71
+ ## 报告问题
72
+
73
+ 私密报告:在本机开 issue 或直接告知维护者,不要在公开渠道贴出可利用细节。
package/accept.mjs ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /** Read-only official-profile installation checks; never claims semantic release readiness. */
3
+ import {readFileSync,existsSync} from 'node:fs'
4
+ import {join,resolve} from 'node:path'
5
+ import {homedir} from 'node:os'
6
+ import {VERSION} from './version.mjs'
7
+ import {managedMemoryStatus} from './index.mjs'
8
+ const args=process.argv.slice(2)
9
+ if(args.length&&!(args.length===2&&args[0]==='--profile'&&/^[a-zA-Z0-9_-]+$/.test(args[1]))){console.error('Usage: node accept.mjs [--profile NAME]');process.exit(2)}
10
+ const profile=args[1]??'desktop',home=resolve(process.env.DSH_HOME??join(homedir(),'.dsh')),dir=join(home,'profiles',profile),root=join(home,'memory'),read=file=>JSON.parse(readFileSync(file,'utf8')),rows=[]
11
+ const check=(name,run)=>{try{rows.push({name,passed:true,...run()})}catch(error){rows.push({name,passed:false,reason:error.code??error.message})}}
12
+ check('official-bundle',()=>{const p=read(join(dir,'package.json'));if(p.dsh?.profile?.bundles?.filter(name=>name==='solopup-memory').length!==1)throw Error('bundle-not-selected-once');if(p.dsh.profile.bundles.includes('dsh-memory'))throw Error('old-and-new-memory-bundles-both-enabled');return{profile}})
13
+ check('installed-package',()=>{const p=read(join(dir,'node_modules','solopup-memory','package.json'));if(p.name!=='solopup-memory'||p.version!==VERSION||p.dsh?.bundle?.patch!=='./cordis.patch.yml')throw Error('installed-package-mismatch');return{version:p.version}})
14
+ check('live-runtime',()=>{const stamp=read(join(root,'.loaded.json')),required=['memory_write','memory_forget','memory_links','memory_search','memory_prune','memory_status'];if(stamp.version!==VERSION||!Number.isSafeInteger(stamp.pid)||stamp.pid<1||!required.every(name=>stamp.tools?.includes(name))||stamp.degraded?.length!==0||stamp.sourceControl?.state!=='managed'||!stamp.memoryHistory?.available||!stamp.autoCapture?.inputRecovery?.available)throw Error('live-runtime-not-ready');process.kill(stamp.pid,0);return{version:stamp.version,pid:stamp.pid,loadedAt:stamp.loadedAt,tools:required.length}})
15
+ check('managed-control',()=>{if(!existsSync(root+'.control-binding.json'))throw Error('control-binding-missing');const s=managedMemoryStatus(root);if(!s.registered||s.stores.some(row=>row.quarantined)||s.operations.some(op=>op.pending))throw Error('managed-control-needs-review-or-cleanup');return{stores:s.stores.length,pending:0}})
16
+ const passed=rows.every(row=>row.passed)
17
+ console.log(JSON.stringify({passed,scope:'read-only installation health, not natural-dialogue or stable-release acceptance',version:VERSION,profile,checks:rows},null,2))
18
+ if(!passed)process.exitCode=1
@@ -0,0 +1,48 @@
1
+ import {observationIdentity} from './tool-observations.mjs'
2
+ /** Reported evidence changes the assessment, never the truth or authority of a claim.
3
+ * Derive on every read from live records: no stale verdict survives source withdrawal.
4
+ */
5
+ const fail=reason=>{throw Error('memory-evidence-'+reason)}
6
+ export function assertRelationTargets(meaning,records){
7
+ for(const relation of meaning?.relations??[]){
8
+ const target=records.find(record=>record.id===relation.target)
9
+ if(!target||!['belief','claim'].includes(target.meaning?.kind))fail('target-not-current-claim')
10
+ // A derived evidence assertion cannot recursively become an independent premise.
11
+ if(target.meaning.relations?.length)fail('target-is-derived-relation')
12
+ }
13
+ }
14
+ /** Source-disjoint means distinct registered roots, not independent real-world events. */
15
+ export function assessBelief(target,records,context,matchEvidence){
16
+ if(!['claim','belief'].includes(target.meaning?.kind)||target.meaning.relations?.length)return undefined
17
+ const rootSet=new Set(target.sources),selected=[];let unknown=0,dependent=0
18
+ for(const record of records){
19
+ const relation=record.meaning?.relations?.find(relation=>relation.target===target.id)
20
+ if(!relation)continue
21
+ const match=matchEvidence(record.meaning,context)
22
+ if(match.state==='not-applicable')continue
23
+ if(match.state==='unknown'){unknown++;continue}
24
+ if(record.observation?.outcome==='error')continue
25
+ const roots=record.observation?[observationIdentity(record.observation)]:record.sources
26
+ if(!roots.length||roots.some(root=>rootSet.has(root))){dependent++;continue}
27
+ selected.push({record,roots,stance:relation.stance})
28
+ }
29
+ // Merge all records connected by any common root, including transitive overlap.
30
+ const parents=selected.map((_,i)=>i),find=i=>parents[i]===i?i:(parents[i]=find(parents[i])),byRoot=new Map()
31
+ for(let i=0;i<selected.length;i++)for(const root of selected[i].roots){if(byRoot.has(root))parents[find(i)]=find(byRoot.get(root));else byRoot.set(root,i)}
32
+ const groups=new Map()
33
+ for(let i=0;i<selected.length;i++){const key=find(i),group=groups.get(key)??new Set();group.add(selected[i].stance);groups.set(key,group)}
34
+ const support=selected.filter(row=>row.stance==='supports'),counter=selected.filter(row=>row.stance==='contradicts')
35
+ const state=support.length&&counter.length?'conflicted':counter.length?'challenged':support.length?'reported-support':'unassessed'
36
+ return{state,assessment:'source-linked-observation-relations',worldVerified:false,nativeOutputRecords:selected.filter(row=>row.record.observation).length,
37
+ supportSourceGroups:[...groups.values()].filter(group=>group.has('supports')).length,
38
+ counterSourceGroups:[...groups.values()].filter(group=>group.has('contradicts')).length,
39
+ mixedSourceGroups:[...groups.values()].filter(group=>group.size>1).length,
40
+ dependentReports:dependent,unknownApplicabilityReports:unknown,
41
+ supportingRecords:support.slice(0,3).map(row=>row.record.id),counterRecords:counter.slice(0,3).map(row=>row.record.id),
42
+ omittedRecords:Math.max(0,support.length-3)+Math.max(0,counter.length-3),coverage:'active-managed-records-only'}
43
+ }
44
+ export function revisionLabel(view){
45
+ const revision=view.revision
46
+ return revision?` 当前证据状态:${revision.state}(revision.state=${revision.state});支持来源组${revision.supportSourceGroups},反向来源组${revision.counterSourceGroups},同根依赖${revision.dependentReports},条件未知${revision.unknownApplicabilityReports}。仅受管现行陈述关系,不是独立验证或置信度。原生输出${revision.nativeOutputRecords}条按相同工具参数/输出合并,不代表现实独立实验。`:''
47
+ }
48
+ export const REVISION_SCHEMA={type:'object',additionalProperties:false,required:['state','assessment','worldVerified','nativeOutputRecords','supportSourceGroups','counterSourceGroups','mixedSourceGroups','dependentReports','unknownApplicabilityReports','supportingRecords','counterRecords','omittedRecords','coverage'],properties:{state:{type:'string',enum:['unassessed','reported-support','challenged','conflicted']},assessment:{type:'string',enum:['source-linked-observation-relations']},worldVerified:{type:'boolean'},nativeOutputRecords:{type:'integer'},supportSourceGroups:{type:'integer'},counterSourceGroups:{type:'integer'},mixedSourceGroups:{type:'integer'},dependentReports:{type:'integer'},unknownApplicabilityReports:{type:'integer'},supportingRecords:{type:'array',items:{type:'string'}},counterRecords:{type:'array',items:{type:'string'}},omittedRecords:{type:'integer'},coverage:{type:'string',enum:['active-managed-records-only']}}}