@zoria-lind/dsh-ecolink-adapter 0.1.2 → 0.2.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/LICENSE +21 -21
- package/README.md +86 -76
- package/adapter/LICENSE +21 -0
- package/adapter/README.md +86 -0
- package/{cordis.patch.yml → adapter/cordis.patch.yml} +19 -19
- package/{src → adapter/src}/config.js +49 -49
- package/{src → adapter/src}/index.js +77 -77
- package/{src → adapter/src}/kernel.js +25 -25
- package/{src → adapter/src}/modules/memoryDiff.js +120 -120
- package/{src → adapter/src}/modules/memoryInject.js +189 -189
- package/{src → adapter/src}/modules/memoryWrite.js +106 -91
- package/{src → adapter/src}/modules/serviceGuard.js +126 -126
- package/extension/core/config.mjs +21 -0
- package/extension/core/harvest.mjs +93 -0
- package/extension/core/prompt.mjs +109 -0
- package/extension/core/queue.mjs +82 -0
- package/extension/core/selector.mjs +88 -0
- package/package.json +18 -18
- package/service/LICENSE +21 -0
- package/service/README.md +87 -0
- package/service/compress.mjs +120 -0
- package/service/config.example.json +6 -0
- package/service/package.json +37 -0
- package/service/pool.mjs +656 -0
- package/service/server.mjs +327 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Zoria Lind
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zoria Lind
|
|
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.md
CHANGED
|
@@ -1,76 +1,86 @@
|
|
|
1
|
-
# dsh-ecolink-adapter
|
|
2
|
-
|
|
3
|
-
dsh-ecolink 的 DSH 适配层(v1):直读本地记忆池(`~/.dsh-memory/memory.json`,只读),
|
|
4
|
-
经 `agent/pre-step` 维持 DSM:memory_write 指令通道(E1),提供 `/ecolink-push` 显式写回(E4)
|
|
5
|
-
与记忆 skill 按需读取(E2),打通"网页端记住 → DSH 直接用;DSH 产出 → 网页端可用"。
|
|
6
|
-
|
|
7
|
-
> **v0.1.1 变更摘要(E0–E8)**:离线队列并发丢条目修复(E0,extension/core/queue.mjs);
|
|
8
|
-
> 指令/内容通道分离——指令每轮幂等注入(plugin 快照消息,不改写用户消息、不碰前缀缓存),
|
|
9
|
-
> 内容默认不注入、由 skill 按需 read,`contentInjectionEnabled` 为逃生舱(E1);
|
|
10
|
-
> 记忆 skill `ecolink-memory` 运行时注册(E2);服务端快照/hash/diff 三端点(E3);
|
|
11
|
-
> `/ecolink-push` 写回(复用 /memory/sync,source:'dsh',service 唯一写者)(E4);
|
|
12
|
-
> 建议确认队列(sync 进队列、确认才入池;未确认条目不进 DSH 上下文)(E5);
|
|
13
|
-
> 网页端只读面板 + chrome.alarms badge(E6);静音 + 黑名单(E7);服务默认安全(E8)。
|
|
14
|
-
>
|
|
15
|
-
> **
|
|
16
|
-
> (
|
|
17
|
-
>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
(
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
1
|
+
# dsh-ecolink-adapter
|
|
2
|
+
|
|
3
|
+
dsh-ecolink 的 DSH 适配层(v1):直读本地记忆池(`~/.dsh-memory/memory.json`,只读),
|
|
4
|
+
经 `agent/pre-step` 维持 DSM:memory_write 指令通道(E1),提供 `/ecolink-push` 显式写回(E4)
|
|
5
|
+
与记忆 skill 按需读取(E2),打通"网页端记住 → DSH 直接用;DSH 产出 → 网页端可用"。
|
|
6
|
+
|
|
7
|
+
> **v0.1.1 变更摘要(E0–E8)**:离线队列并发丢条目修复(E0,extension/core/queue.mjs);
|
|
8
|
+
> 指令/内容通道分离——指令每轮幂等注入(plugin 快照消息,不改写用户消息、不碰前缀缓存),
|
|
9
|
+
> 内容默认不注入、由 skill 按需 read,`contentInjectionEnabled` 为逃生舱(E1);
|
|
10
|
+
> 记忆 skill `ecolink-memory` 运行时注册(E2);服务端快照/hash/diff 三端点(E3);
|
|
11
|
+
> `/ecolink-push` 写回(复用 /memory/sync,source:'dsh',service 唯一写者)(E4);
|
|
12
|
+
> 建议确认队列(sync 进队列、确认才入池;未确认条目不进 DSH 上下文)(E5);
|
|
13
|
+
> 网页端只读面板 + chrome.alarms badge(E6);静音 + 黑名单(E7);服务默认安全(E8)。
|
|
14
|
+
>
|
|
15
|
+
> **v0.2.0(2026-09-25,与 service/extension 同号发布)**:压缩体系重构在 service/扩展侧
|
|
16
|
+
> (事务暂存池 → 模型自报重复数动态下限 → 提交/回滚,详见 service/README.md);
|
|
17
|
+
> adapter 侧:install 方式改为 npm 包安装(`dsh plugin add @zoria-lind/dsh-ecolink-adapter`),
|
|
18
|
+
> bundle patch 的 `name` 已改为 scoped 包名(修复 npm 安装 `cannot resolve package`)。
|
|
19
|
+
>
|
|
20
|
+
> **v1.1(2026-09-14)**:service 自动拉起——探测到 17520 未监听就本机 spawn 拉起
|
|
21
|
+
> (apply + pre-step 60s 节流;仅本地 URL;`serviceAutoStart` 默认开)。E5 设计纠正:
|
|
22
|
+
> 确认点改到 DSH 侧(待实现),随仓 config.json 设 `autoConfirm: true`,网页收割直入池。
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# npm 安装(0.2.0 起推荐)
|
|
28
|
+
dsh plugin --profile web add @zoria-lind/dsh-ecolink-adapter
|
|
29
|
+
|
|
30
|
+
# 或本地路径(开发)
|
|
31
|
+
dsh plugin --profile web add D:/dsh/dsh-plugins/dsh-ecolink/adapter
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 机制
|
|
35
|
+
|
|
36
|
+
- **只读池文件**:mtime 缓存(文件变化立即重读,TTL 5s 兜底);唯一写者是 ecolink-service
|
|
37
|
+
- **指令通道(E1,默认开)**:每轮 pre-step 末尾追加一条 `source.kind='plugin'` 的
|
|
38
|
+
`[dsh-ecolink 指令]` 快照消息(照抄内核 dsh-time-context 形态:prepend 注册 + await next +
|
|
39
|
+
createUserMessage;决策里的 messages 只喂本步请求、不写会话事件)。剥旧追加 → 每轮幂等不叠加
|
|
40
|
+
- **内容通道(E1,默认关)**:`contentInjectionEnabled: true` 恢复旧行为——改写用户消息注入
|
|
41
|
+
记忆块(2-gram 打分 + 时间衰减 + 预算 + 长提示词缩减 + singleInjection 会话去重)
|
|
42
|
+
- **`/ecolink-push`(E4)**:斜杠命令,把指定要点 POST 到 service 的 `/memory/sync`
|
|
43
|
+
(source:'dsh');token 未配置时自动读同仓 `service/config.json`;service 是唯一写者
|
|
44
|
+
- **记忆 skill(E2)**:注册 `ecolink-memory`,指引模型用 read 按需读池原文(引用前必须核对)
|
|
45
|
+
- **service 自动拉起(v1.1)**:apply 时与每次 pre-step(60s 节流)探测 `serviceUrl/memory/status`;
|
|
46
|
+
任何 HTTP 响应(含 401)= 已活;网络错误 = 未运行 → spawn 同仓 `service/server.mjs`
|
|
47
|
+
(detached + 无窗口)。仅对 127.0.0.1/localhost/::1 生效;service 目录缺失(独立发布包)静默跳过。
|
|
48
|
+
与登录自启任务兼容:端口已监听就不会重复起
|
|
49
|
+
- **fail-open**:池不存在/读失败/任何异常 → 静默放行,绝不破坏请求
|
|
50
|
+
- 只处理 `source.kind='user'` 的真实用户消息(DSH runtime-context 快照直接放行)
|
|
51
|
+
|
|
52
|
+
## 配置(cordis.patch.yml)
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
adapter:
|
|
56
|
+
enabled: true
|
|
57
|
+
poolPath: '~/.dsh-memory/memory.json'
|
|
58
|
+
poolTtlMs: 5000
|
|
59
|
+
injectEnabled: true # 总开关(false = 两个通道全关)
|
|
60
|
+
singleInjection: true # 内容通道专用(指令通道天然每轮幂等)
|
|
61
|
+
maxInjectionChars: 3000 # 内容通道注入预算
|
|
62
|
+
instructionEnabled: true # E1 指令通道
|
|
63
|
+
contentInjectionEnabled: false # E1 内容逃生舱
|
|
64
|
+
skillName: 'ecolink-memory' # E2 skill 注册名
|
|
65
|
+
serviceUrl: 'http://127.0.0.1:17520' # E4 写回目标
|
|
66
|
+
serviceToken: '' # E4;留空自动读同仓 service/config.json(E8 自动生成)
|
|
67
|
+
serviceAutoStart: true # v1.1;探测到服务未运行就自动拉起(仅本地 URL 生效)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 测试
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node adapter/test/smoke.mjs # 76 项,零 API
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 已知限制
|
|
77
|
+
|
|
78
|
+
- 会话过滤靠 `#记忆名` 显式调用;DSH CLI 的 `--resume <session>` 只接受会话 id,
|
|
79
|
+
"按命名会话自动绑定"待 DSH 提供 `--session` 能力后再做
|
|
80
|
+
- 与 token-optimizer / behavior-enhancer 的联动开关(两插件中 `memory_bridge` 占位节)
|
|
81
|
+
待适配层稳定后启用
|
|
82
|
+
- `inject.js` 仍是经典脚本,INSTRUCTION_PROMPT/BLOCK_RE 等与 core/*.mjs 镜像维护
|
|
83
|
+
(注释锁死);彻底消除镜像需要构建期注入(P5/0D 结论)
|
|
84
|
+
- npm 发布口径(0.1.3 起已解决):`src/modules/memoryInject.js` 跨目录 import `extension/core/*`,
|
|
85
|
+
发布时经 `scripts/build-npm-pkgs.mjs` 生成镜像仓库布局的 staging 包
|
|
86
|
+
(adapter/+extension/core/+service/ 平铺),发布前必须 `npm pack` 解包实测 import 链
|
package/adapter/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zoria Lind
|
|
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.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# dsh-ecolink-adapter
|
|
2
|
+
|
|
3
|
+
dsh-ecolink 的 DSH 适配层(v1):直读本地记忆池(`~/.dsh-memory/memory.json`,只读),
|
|
4
|
+
经 `agent/pre-step` 维持 DSM:memory_write 指令通道(E1),提供 `/ecolink-push` 显式写回(E4)
|
|
5
|
+
与记忆 skill 按需读取(E2),打通"网页端记住 → DSH 直接用;DSH 产出 → 网页端可用"。
|
|
6
|
+
|
|
7
|
+
> **v0.1.1 变更摘要(E0–E8)**:离线队列并发丢条目修复(E0,extension/core/queue.mjs);
|
|
8
|
+
> 指令/内容通道分离——指令每轮幂等注入(plugin 快照消息,不改写用户消息、不碰前缀缓存),
|
|
9
|
+
> 内容默认不注入、由 skill 按需 read,`contentInjectionEnabled` 为逃生舱(E1);
|
|
10
|
+
> 记忆 skill `ecolink-memory` 运行时注册(E2);服务端快照/hash/diff 三端点(E3);
|
|
11
|
+
> `/ecolink-push` 写回(复用 /memory/sync,source:'dsh',service 唯一写者)(E4);
|
|
12
|
+
> 建议确认队列(sync 进队列、确认才入池;未确认条目不进 DSH 上下文)(E5);
|
|
13
|
+
> 网页端只读面板 + chrome.alarms badge(E6);静音 + 黑名单(E7);服务默认安全(E8)。
|
|
14
|
+
>
|
|
15
|
+
> **v0.2.0(2026-09-25,与 service/extension 同号发布)**:压缩体系重构在 service/扩展侧
|
|
16
|
+
> (事务暂存池 → 模型自报重复数动态下限 → 提交/回滚,详见 service/README.md);
|
|
17
|
+
> adapter 侧:install 方式改为 npm 包安装(`dsh plugin add @zoria-lind/dsh-ecolink-adapter`),
|
|
18
|
+
> bundle patch 的 `name` 已改为 scoped 包名(修复 npm 安装 `cannot resolve package`)。
|
|
19
|
+
>
|
|
20
|
+
> **v1.1(2026-09-14)**:service 自动拉起——探测到 17520 未监听就本机 spawn 拉起
|
|
21
|
+
> (apply + pre-step 60s 节流;仅本地 URL;`serviceAutoStart` 默认开)。E5 设计纠正:
|
|
22
|
+
> 确认点改到 DSH 侧(待实现),随仓 config.json 设 `autoConfirm: true`,网页收割直入池。
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# npm 安装(0.2.0 起推荐)
|
|
28
|
+
dsh plugin --profile web add @zoria-lind/dsh-ecolink-adapter
|
|
29
|
+
|
|
30
|
+
# 或本地路径(开发)
|
|
31
|
+
dsh plugin --profile web add D:/dsh/dsh-plugins/dsh-ecolink/adapter
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 机制
|
|
35
|
+
|
|
36
|
+
- **只读池文件**:mtime 缓存(文件变化立即重读,TTL 5s 兜底);唯一写者是 ecolink-service
|
|
37
|
+
- **指令通道(E1,默认开)**:每轮 pre-step 末尾追加一条 `source.kind='plugin'` 的
|
|
38
|
+
`[dsh-ecolink 指令]` 快照消息(照抄内核 dsh-time-context 形态:prepend 注册 + await next +
|
|
39
|
+
createUserMessage;决策里的 messages 只喂本步请求、不写会话事件)。剥旧追加 → 每轮幂等不叠加
|
|
40
|
+
- **内容通道(E1,默认关)**:`contentInjectionEnabled: true` 恢复旧行为——改写用户消息注入
|
|
41
|
+
记忆块(2-gram 打分 + 时间衰减 + 预算 + 长提示词缩减 + singleInjection 会话去重)
|
|
42
|
+
- **`/ecolink-push`(E4)**:斜杠命令,把指定要点 POST 到 service 的 `/memory/sync`
|
|
43
|
+
(source:'dsh');token 未配置时自动读同仓 `service/config.json`;service 是唯一写者
|
|
44
|
+
- **记忆 skill(E2)**:注册 `ecolink-memory`,指引模型用 read 按需读池原文(引用前必须核对)
|
|
45
|
+
- **service 自动拉起(v1.1)**:apply 时与每次 pre-step(60s 节流)探测 `serviceUrl/memory/status`;
|
|
46
|
+
任何 HTTP 响应(含 401)= 已活;网络错误 = 未运行 → spawn 同仓 `service/server.mjs`
|
|
47
|
+
(detached + 无窗口)。仅对 127.0.0.1/localhost/::1 生效;service 目录缺失(独立发布包)静默跳过。
|
|
48
|
+
与登录自启任务兼容:端口已监听就不会重复起
|
|
49
|
+
- **fail-open**:池不存在/读失败/任何异常 → 静默放行,绝不破坏请求
|
|
50
|
+
- 只处理 `source.kind='user'` 的真实用户消息(DSH runtime-context 快照直接放行)
|
|
51
|
+
|
|
52
|
+
## 配置(cordis.patch.yml)
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
adapter:
|
|
56
|
+
enabled: true
|
|
57
|
+
poolPath: '~/.dsh-memory/memory.json'
|
|
58
|
+
poolTtlMs: 5000
|
|
59
|
+
injectEnabled: true # 总开关(false = 两个通道全关)
|
|
60
|
+
singleInjection: true # 内容通道专用(指令通道天然每轮幂等)
|
|
61
|
+
maxInjectionChars: 3000 # 内容通道注入预算
|
|
62
|
+
instructionEnabled: true # E1 指令通道
|
|
63
|
+
contentInjectionEnabled: false # E1 内容逃生舱
|
|
64
|
+
skillName: 'ecolink-memory' # E2 skill 注册名
|
|
65
|
+
serviceUrl: 'http://127.0.0.1:17520' # E4 写回目标
|
|
66
|
+
serviceToken: '' # E4;留空自动读同仓 service/config.json(E8 自动生成)
|
|
67
|
+
serviceAutoStart: true # v1.1;探测到服务未运行就自动拉起(仅本地 URL 生效)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 测试
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
node adapter/test/smoke.mjs # 76 项,零 API
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 已知限制
|
|
77
|
+
|
|
78
|
+
- 会话过滤靠 `#记忆名` 显式调用;DSH CLI 的 `--resume <session>` 只接受会话 id,
|
|
79
|
+
"按命名会话自动绑定"待 DSH 提供 `--session` 能力后再做
|
|
80
|
+
- 与 token-optimizer / behavior-enhancer 的联动开关(两插件中 `memory_bridge` 占位节)
|
|
81
|
+
待适配层稳定后启用
|
|
82
|
+
- `inject.js` 仍是经典脚本,INSTRUCTION_PROMPT/BLOCK_RE 等与 core/*.mjs 镜像维护
|
|
83
|
+
(注释锁死);彻底消除镜像需要构建期注入(P5/0D 结论)
|
|
84
|
+
- npm 发布口径(0.1.3 起已解决):`src/modules/memoryInject.js` 跨目录 import `extension/core/*`,
|
|
85
|
+
发布时经 `scripts/build-npm-pkgs.mjs` 生成镜像仓库布局的 staging 包
|
|
86
|
+
(adapter/+extension/core/+service/ 平铺),发布前必须 `npm pack` 解包实测 import 链
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
# dsh-ecolink-adapter bundle layer:挂载适配层。
|
|
2
|
-
- insert:
|
|
3
|
-
- id: ecolink-adapter
|
|
4
|
-
name: 'dsh-ecolink-adapter'
|
|
5
|
-
config:
|
|
6
|
-
adapter:
|
|
7
|
-
enabled: true
|
|
8
|
-
poolPath: '~/.dsh-memory/memory.json'
|
|
9
|
-
poolTtlMs: 5000
|
|
10
|
-
injectEnabled: true
|
|
11
|
-
singleInjection: true
|
|
12
|
-
maxInjectionChars: 3000
|
|
13
|
-
# E1 通道分离:指令每轮幂等注入;内容默认不注入(按需 read,见 skill)
|
|
14
|
-
instructionEnabled: true
|
|
15
|
-
contentInjectionEnabled: false # 逃生舱:true 恢复旧的"改写用户消息注入记忆块"行为
|
|
16
|
-
skillName: 'ecolink-memory' # E2 记忆 skill 注册名
|
|
17
|
-
# E4 写回:/ecolink-push 经 service 的 POST /memory/sync 落盘(唯一写者)
|
|
18
|
-
serviceUrl: 'http://127.0.0.1:17520'
|
|
19
|
-
serviceToken: '' # 留空自动读同仓 service/config.json 的 token(E8 自动生成)
|
|
1
|
+
# dsh-ecolink-adapter bundle layer:挂载适配层。
|
|
2
|
+
- insert:
|
|
3
|
+
- id: ecolink-adapter
|
|
4
|
+
name: '@zoria-lind/dsh-ecolink-adapter'
|
|
5
|
+
config:
|
|
6
|
+
adapter:
|
|
7
|
+
enabled: true
|
|
8
|
+
poolPath: '~/.dsh-memory/memory.json'
|
|
9
|
+
poolTtlMs: 5000
|
|
10
|
+
injectEnabled: true
|
|
11
|
+
singleInjection: true
|
|
12
|
+
maxInjectionChars: 3000
|
|
13
|
+
# E1 通道分离:指令每轮幂等注入;内容默认不注入(按需 read,见 skill)
|
|
14
|
+
instructionEnabled: true
|
|
15
|
+
contentInjectionEnabled: false # 逃生舱:true 恢复旧的"改写用户消息注入记忆块"行为
|
|
16
|
+
skillName: 'ecolink-memory' # E2 记忆 skill 注册名
|
|
17
|
+
# E4 写回:/ecolink-push 经 service 的 POST /memory/sync 落盘(唯一写者)
|
|
18
|
+
serviceUrl: 'http://127.0.0.1:17520'
|
|
19
|
+
serviceToken: '' # 留空自动读同仓 service/config.json 的 token(E8 自动生成)
|
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
// dsh-ecolink-adapter 配置。与 token-optimizer / behavior-enhancer 同款 resolveSection 模式。
|
|
2
|
-
|
|
3
|
-
export const DEFAULT_CONFIG = {
|
|
4
|
-
adapter: {
|
|
5
|
-
enabled: true,
|
|
6
|
-
poolPath: '~/.dsh-memory/memory.json', // 只读;唯一写者是 ecolink-service
|
|
7
|
-
poolTtlMs: 5000, // 池文件缓存(mtime 变化立即重读,否则 TTL 兜底)
|
|
8
|
-
injectEnabled: true, // 总开关(false = 两个通道全关)
|
|
9
|
-
singleInjection: true, // 内容通道专用:每 DSH 会话只注入一次(指令通道天然每轮幂等,不适用)
|
|
10
|
-
maxInjectionChars: 3000, // 内容通道注入预算(长提示词自动缩减,与网页端同规则)
|
|
11
|
-
// E1 通道分离:指令每轮幂等注入(维持 DSM:memory_write 捕获);内容默认不再注入
|
|
12
|
-
instructionEnabled: true, // 指令通道(pre-step 追加 plugin 快照消息)
|
|
13
|
-
contentInjectionEnabled: false, // 内容通道逃生舱(旧行为:改写用户消息注入记忆块)
|
|
14
|
-
skillName: 'ecolink-memory', // E2 记忆 skill 的注册名(kebab-case)
|
|
15
|
-
// E4 写回:POST /memory/sync 到本机 service(service 是唯一写者,DSH 只发请求)
|
|
16
|
-
serviceUrl: 'http://127.0.0.1:17520',
|
|
17
|
-
serviceToken: '', // 留空则自动读同仓 service/config.json 的 token(E8 自动生成)
|
|
18
|
-
serviceAutoStart: true, // v1.1:探测到 service 未运行就自动拉起(仅本地 URL;见 serviceGuard.js)
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const NUMERIC_KEYS = new Set(['poolTtlMs', 'maxInjectionChars'])
|
|
23
|
-
|
|
24
|
-
function resolveSection(section, defaults) {
|
|
25
|
-
const out = { ...defaults }
|
|
26
|
-
if (section && typeof section === 'object') {
|
|
27
|
-
for (const [key, value] of Object.entries(section)) {
|
|
28
|
-
if (!(key in defaults)) {
|
|
29
|
-
throw new Error(`dsh-ecolink-adapter config: unknown key "${key}" (allowed: ${Object.keys(defaults).join(', ')})`)
|
|
30
|
-
}
|
|
31
|
-
if (NUMERIC_KEYS.has(key)) {
|
|
32
|
-
if (!Number.isFinite(value) || value <= 0) {
|
|
33
|
-
throw new Error(`dsh-ecolink-adapter config: ${key} (${value}) must be a positive number`)
|
|
34
|
-
}
|
|
35
|
-
} else if (typeof value !== typeof defaults[key]) {
|
|
36
|
-
throw new Error(`dsh-ecolink-adapter config: "${key}" must be ${typeof defaults[key]}`)
|
|
37
|
-
}
|
|
38
|
-
out[key] = value
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return Object.freeze(out)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function resolveConfig(config = {}) {
|
|
45
|
-
if (typeof config !== 'object' || config === null) config = {}
|
|
46
|
-
return Object.freeze({
|
|
47
|
-
adapter: resolveSection(config.adapter, DEFAULT_CONFIG.adapter),
|
|
48
|
-
})
|
|
49
|
-
}
|
|
1
|
+
// dsh-ecolink-adapter 配置。与 token-optimizer / behavior-enhancer 同款 resolveSection 模式。
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_CONFIG = {
|
|
4
|
+
adapter: {
|
|
5
|
+
enabled: true,
|
|
6
|
+
poolPath: '~/.dsh-memory/memory.json', // 只读;唯一写者是 ecolink-service
|
|
7
|
+
poolTtlMs: 5000, // 池文件缓存(mtime 变化立即重读,否则 TTL 兜底)
|
|
8
|
+
injectEnabled: true, // 总开关(false = 两个通道全关)
|
|
9
|
+
singleInjection: true, // 内容通道专用:每 DSH 会话只注入一次(指令通道天然每轮幂等,不适用)
|
|
10
|
+
maxInjectionChars: 3000, // 内容通道注入预算(长提示词自动缩减,与网页端同规则)
|
|
11
|
+
// E1 通道分离:指令每轮幂等注入(维持 DSM:memory_write 捕获);内容默认不再注入
|
|
12
|
+
instructionEnabled: true, // 指令通道(pre-step 追加 plugin 快照消息)
|
|
13
|
+
contentInjectionEnabled: false, // 内容通道逃生舱(旧行为:改写用户消息注入记忆块)
|
|
14
|
+
skillName: 'ecolink-memory', // E2 记忆 skill 的注册名(kebab-case)
|
|
15
|
+
// E4 写回:POST /memory/sync 到本机 service(service 是唯一写者,DSH 只发请求)
|
|
16
|
+
serviceUrl: 'http://127.0.0.1:17520',
|
|
17
|
+
serviceToken: '', // 留空则自动读同仓 service/config.json 的 token(E8 自动生成)
|
|
18
|
+
serviceAutoStart: true, // v1.1:探测到 service 未运行就自动拉起(仅本地 URL;见 serviceGuard.js)
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const NUMERIC_KEYS = new Set(['poolTtlMs', 'maxInjectionChars'])
|
|
23
|
+
|
|
24
|
+
function resolveSection(section, defaults) {
|
|
25
|
+
const out = { ...defaults }
|
|
26
|
+
if (section && typeof section === 'object') {
|
|
27
|
+
for (const [key, value] of Object.entries(section)) {
|
|
28
|
+
if (!(key in defaults)) {
|
|
29
|
+
throw new Error(`dsh-ecolink-adapter config: unknown key "${key}" (allowed: ${Object.keys(defaults).join(', ')})`)
|
|
30
|
+
}
|
|
31
|
+
if (NUMERIC_KEYS.has(key)) {
|
|
32
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
33
|
+
throw new Error(`dsh-ecolink-adapter config: ${key} (${value}) must be a positive number`)
|
|
34
|
+
}
|
|
35
|
+
} else if (typeof value !== typeof defaults[key]) {
|
|
36
|
+
throw new Error(`dsh-ecolink-adapter config: "${key}" must be ${typeof defaults[key]}`)
|
|
37
|
+
}
|
|
38
|
+
out[key] = value
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return Object.freeze(out)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function resolveConfig(config = {}) {
|
|
45
|
+
if (typeof config !== 'object' || config === null) config = {}
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
adapter: resolveSection(config.adapter, DEFAULT_CONFIG.adapter),
|
|
48
|
+
})
|
|
49
|
+
}
|
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
// dsh-ecolink-adapter(E1/E2):dsh-ecolink 的 DSH 适配层。
|
|
2
|
-
// 职责(PLAN §6/§8):直读 memory.json(只读,唯一写者是 ecolink-service),
|
|
3
|
-
// pre-step 指令通道(每轮幂等追加 plugin 快照消息,E1)+ 可选内容注入逃生舱 +
|
|
4
|
-
// 记忆 skill 运行时注册(E2:内容按需 read),与网页端记忆生态打通。
|
|
5
|
-
// 与 token-optimizer / behavior-enhancer 的联动开关(memory_bridge 配置节)已
|
|
6
|
-
// 在两者中占位,等适配层稳定后在各自 README 说明如何开启。
|
|
7
|
-
|
|
8
|
-
import { DEFAULT_CONFIG, resolveConfig } from './config.js'
|
|
9
|
-
import { createMemoryInjectModule } from './modules/memoryInject.js'
|
|
10
|
-
import { createMemoryWriteModule } from './modules/memoryWrite.js'
|
|
11
|
-
import { createServiceGuardModule } from './modules/serviceGuard.js'
|
|
12
|
-
import { createMemoryDiffModule } from './modules/memoryDiff.js'
|
|
13
|
-
|
|
14
|
-
// E2 记忆 skill 正文:指引模型按需 read 记忆池(内容不再自动注入,这里是读取入口)。
|
|
15
|
-
// 引用细节前必须 read 原文核对(沿用 token-optimizer 的堵漏原则)。
|
|
16
|
-
const SKILL_CONTENT = `# dsh-ecolink 跨端记忆池
|
|
17
|
-
|
|
18
|
-
本机记忆池文件:\`~/.dsh-memory/memory.json\`(归档:\`~/.dsh-memory/archive.json\`)。
|
|
19
|
-
网页端(chat.deepseek.com)与 DSH 共用这一份结构化池;网页端记过的事实在这里能查到。
|
|
20
|
-
|
|
21
|
-
## 文件结构
|
|
22
|
-
- 顶层:{ version, shared_pool: [...], session_pools: { <网页会话id>: { identity, memories: [...] } } }
|
|
23
|
-
- 条目字段:id / key / content / timestamp(UTC ISO) / time_precision / source(web|dsm-import|dsh) / importance(always|called) / pinned / last_accessed
|
|
24
|
-
- shared_pool 是跨会话共享记忆;session_pools 按网页会话分组,identity 是该会话的人类可读名
|
|
25
|
-
|
|
26
|
-
## 何时读
|
|
27
|
-
- 用户提到"我在网页端记过 / 之前说过 / 我的偏好"等跨端记忆问题时
|
|
28
|
-
- 需要回忆历史偏好、项目约定、个人事实,而当前上下文没有答案时
|
|
29
|
-
|
|
30
|
-
## 使用规则
|
|
31
|
-
- 先运行 /ecolink-diff 命令获取记忆池自上次查看以来的新增/变化(本会话或重启后首次调用会返回全量)——多数问题只靠这个结果就能答
|
|
32
|
-
- 禁止在未查询记忆池的情况下回答"不知道/不记得/没有记录":记忆池与本对话上下文是两回事,池里有而上下文没有是常态
|
|
33
|
-
- 需要核对细节或完整历史时,用 read 工具读取 memory.json 原文;引用任何记忆细节前必须先读到原文,禁止凭印象回答
|
|
34
|
-
- timestamp 是 UTC 存储值(例:2026-09-14T10:24Z = 本地 18:24,本机时区 UTC+8)。展示给用户时**必须先转本地时间**,再按龄降精度:2 小时内→分钟,48 小时内→小时,5 天内→日期,更早不显示时间;禁止直接把 UTC 原值当本地时间展示
|
|
35
|
-
- 记忆可能过时:时间戳较旧或与当前对话矛盾时,先向用户复述该记忆并确认,不要当作当前事实直接使用
|
|
36
|
-
`
|
|
37
|
-
|
|
38
|
-
export function apply(ctx, config = {}) {
|
|
39
|
-
const resolved = resolveConfig(config)
|
|
40
|
-
const stats = { bump() {}, addSample() {}, dispose() {}, snapshot() { return {} } }
|
|
41
|
-
const modules = []
|
|
42
|
-
modules.push(createMemoryInjectModule(ctx, resolved.adapter, stats))
|
|
43
|
-
// E4:DSH 记忆写回(/ecolink-push 显式触发;service 是唯一写者)
|
|
44
|
-
modules.push(createMemoryWriteModule(ctx, resolved.adapter, stats))
|
|
45
|
-
// E9:记忆 diff 查看(/ecolink-diff;调用即读取事件,游标随调用推进,skill 优先走这条)
|
|
46
|
-
modules.push(createMemoryDiffModule(ctx, resolved.adapter, stats))
|
|
47
|
-
// v1.1:service 未运行时自动拉起(先探测后 spawn,已在跑就不会重复起)
|
|
48
|
-
modules.push(createServiceGuardModule(ctx, resolved.adapter, stats))
|
|
49
|
-
|
|
50
|
-
// E2:记忆 skill 运行时注册(register 返回 Cordis disposer,非 Promise;
|
|
51
|
-
// 同名重复注册是 first-wins + no-op disposer,重复挂载不会叠加)。
|
|
52
|
-
// inject 依赖缺失时本回调永不执行(插件其余部分不受影响)。
|
|
53
|
-
const skillDisposers = []
|
|
54
|
-
ctx.inject?.(['skills'], (skillCtx) => {
|
|
55
|
-
try {
|
|
56
|
-
skillDisposers.push(skillCtx.skills.register({
|
|
57
|
-
name: resolved.adapter.skillName,
|
|
58
|
-
description: '按需读取 dsh-ecolink 跨端记忆池(~/.dsh-memory/memory.json)',
|
|
59
|
-
whenToUse: '需要回忆网页端记过的偏好/事实/决策,或用户提到之前记过的内容时',
|
|
60
|
-
content: SKILL_CONTENT,
|
|
61
|
-
source: 'runtime',
|
|
62
|
-
}))
|
|
63
|
-
} catch (err) {
|
|
64
|
-
console.warn(`[dsh-ecolink-adapter] skill 注册失败(${err?.message ?? err})`)
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
return () => {
|
|
69
|
-
for (const cleanup of modules) cleanup()
|
|
70
|
-
for (const dispose of skillDisposers) {
|
|
71
|
-
try { dispose?.() } catch { /* noop */ }
|
|
72
|
-
}
|
|
73
|
-
stats.dispose()
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export { DEFAULT_CONFIG, resolveConfig }
|
|
1
|
+
// dsh-ecolink-adapter(E1/E2):dsh-ecolink 的 DSH 适配层。
|
|
2
|
+
// 职责(PLAN §6/§8):直读 memory.json(只读,唯一写者是 ecolink-service),
|
|
3
|
+
// pre-step 指令通道(每轮幂等追加 plugin 快照消息,E1)+ 可选内容注入逃生舱 +
|
|
4
|
+
// 记忆 skill 运行时注册(E2:内容按需 read),与网页端记忆生态打通。
|
|
5
|
+
// 与 token-optimizer / behavior-enhancer 的联动开关(memory_bridge 配置节)已
|
|
6
|
+
// 在两者中占位,等适配层稳定后在各自 README 说明如何开启。
|
|
7
|
+
|
|
8
|
+
import { DEFAULT_CONFIG, resolveConfig } from './config.js'
|
|
9
|
+
import { createMemoryInjectModule } from './modules/memoryInject.js'
|
|
10
|
+
import { createMemoryWriteModule } from './modules/memoryWrite.js'
|
|
11
|
+
import { createServiceGuardModule } from './modules/serviceGuard.js'
|
|
12
|
+
import { createMemoryDiffModule } from './modules/memoryDiff.js'
|
|
13
|
+
|
|
14
|
+
// E2 记忆 skill 正文:指引模型按需 read 记忆池(内容不再自动注入,这里是读取入口)。
|
|
15
|
+
// 引用细节前必须 read 原文核对(沿用 token-optimizer 的堵漏原则)。
|
|
16
|
+
const SKILL_CONTENT = `# dsh-ecolink 跨端记忆池
|
|
17
|
+
|
|
18
|
+
本机记忆池文件:\`~/.dsh-memory/memory.json\`(归档:\`~/.dsh-memory/archive.json\`)。
|
|
19
|
+
网页端(chat.deepseek.com)与 DSH 共用这一份结构化池;网页端记过的事实在这里能查到。
|
|
20
|
+
|
|
21
|
+
## 文件结构
|
|
22
|
+
- 顶层:{ version, shared_pool: [...], session_pools: { <网页会话id>: { identity, memories: [...] } } }
|
|
23
|
+
- 条目字段:id / key / content / timestamp(UTC ISO) / time_precision / source(web|dsm-import|dsh) / importance(always|called) / pinned / last_accessed
|
|
24
|
+
- shared_pool 是跨会话共享记忆;session_pools 按网页会话分组,identity 是该会话的人类可读名
|
|
25
|
+
|
|
26
|
+
## 何时读
|
|
27
|
+
- 用户提到"我在网页端记过 / 之前说过 / 我的偏好"等跨端记忆问题时
|
|
28
|
+
- 需要回忆历史偏好、项目约定、个人事实,而当前上下文没有答案时
|
|
29
|
+
|
|
30
|
+
## 使用规则
|
|
31
|
+
- 先运行 /ecolink-diff 命令获取记忆池自上次查看以来的新增/变化(本会话或重启后首次调用会返回全量)——多数问题只靠这个结果就能答
|
|
32
|
+
- 禁止在未查询记忆池的情况下回答"不知道/不记得/没有记录":记忆池与本对话上下文是两回事,池里有而上下文没有是常态
|
|
33
|
+
- 需要核对细节或完整历史时,用 read 工具读取 memory.json 原文;引用任何记忆细节前必须先读到原文,禁止凭印象回答
|
|
34
|
+
- timestamp 是 UTC 存储值(例:2026-09-14T10:24Z = 本地 18:24,本机时区 UTC+8)。展示给用户时**必须先转本地时间**,再按龄降精度:2 小时内→分钟,48 小时内→小时,5 天内→日期,更早不显示时间;禁止直接把 UTC 原值当本地时间展示
|
|
35
|
+
- 记忆可能过时:时间戳较旧或与当前对话矛盾时,先向用户复述该记忆并确认,不要当作当前事实直接使用
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
export function apply(ctx, config = {}) {
|
|
39
|
+
const resolved = resolveConfig(config)
|
|
40
|
+
const stats = { bump() {}, addSample() {}, dispose() {}, snapshot() { return {} } }
|
|
41
|
+
const modules = []
|
|
42
|
+
modules.push(createMemoryInjectModule(ctx, resolved.adapter, stats))
|
|
43
|
+
// E4:DSH 记忆写回(/ecolink-push 显式触发;service 是唯一写者)
|
|
44
|
+
modules.push(createMemoryWriteModule(ctx, resolved.adapter, stats))
|
|
45
|
+
// E9:记忆 diff 查看(/ecolink-diff;调用即读取事件,游标随调用推进,skill 优先走这条)
|
|
46
|
+
modules.push(createMemoryDiffModule(ctx, resolved.adapter, stats))
|
|
47
|
+
// v1.1:service 未运行时自动拉起(先探测后 spawn,已在跑就不会重复起)
|
|
48
|
+
modules.push(createServiceGuardModule(ctx, resolved.adapter, stats))
|
|
49
|
+
|
|
50
|
+
// E2:记忆 skill 运行时注册(register 返回 Cordis disposer,非 Promise;
|
|
51
|
+
// 同名重复注册是 first-wins + no-op disposer,重复挂载不会叠加)。
|
|
52
|
+
// inject 依赖缺失时本回调永不执行(插件其余部分不受影响)。
|
|
53
|
+
const skillDisposers = []
|
|
54
|
+
ctx.inject?.(['skills'], (skillCtx) => {
|
|
55
|
+
try {
|
|
56
|
+
skillDisposers.push(skillCtx.skills.register({
|
|
57
|
+
name: resolved.adapter.skillName,
|
|
58
|
+
description: '按需读取 dsh-ecolink 跨端记忆池(~/.dsh-memory/memory.json)',
|
|
59
|
+
whenToUse: '需要回忆网页端记过的偏好/事实/决策,或用户提到之前记过的内容时',
|
|
60
|
+
content: SKILL_CONTENT,
|
|
61
|
+
source: 'runtime',
|
|
62
|
+
}))
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.warn(`[dsh-ecolink-adapter] skill 注册失败(${err?.message ?? err})`)
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
return () => {
|
|
69
|
+
for (const cleanup of modules) cleanup()
|
|
70
|
+
for (const dispose of skillDisposers) {
|
|
71
|
+
try { dispose?.() } catch { /* noop */ }
|
|
72
|
+
}
|
|
73
|
+
stats.dispose()
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { DEFAULT_CONFIG, resolveConfig }
|