@furongjun1999/dsh-memory 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/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # @furongjun1999/dsh-memory
2
+
3
+ **灵枢(AEIS)× DeepSeek Harness 插件**:把灵枢的时空记忆/知识飞轮/自我认知接入 DSH,
4
+ 让 Agent 拥有跨会话的长期记忆与认知能力。
5
+
6
+ > 灵枢(AEIS)是一个遵循「智能论 v3.2」协议的时空记忆引擎:五层记忆(锚点/结构/知识/情境/自我)、
7
+ > 知识飞轮(验证→归纳→联想→蒸馏→推演)、自我认知循环(P0 系列)、外部知识摄取。
8
+ > 本插件是它在 DeepSeek Harness 生态中的桥。
9
+
10
+ ## 特性
11
+
12
+ - **工具桥接**:Agent 可直接调用 `lingxu_remember / recall / search / think` 等灵枢能力
13
+ (默认精选 12 个核心工具,可切换全部或自定义集合)
14
+ - **自动记忆**:DSH 对话自动沉淀进灵枢记忆库——用户消息带重要性写入、去重,随会话累积
15
+ - **动态 schema**:工具清单运行时从灵枢 `tools/list` 实时拉取,灵枢升级新增工具 DSH 侧零改动
16
+ - **零运行时依赖**:手写 stdio MCP 桥(不依赖 MCP SDK),与灵枢 D-005「核心零外部依赖」工程哲学一致
17
+ - **进程自愈**:灵枢 Python 子进程崩溃自动指数退避重启(1s→30s),插件卸载优雅退出
18
+
19
+ ## 架构
20
+
21
+ ```
22
+ ┌─────────────────────────────────────────────┐
23
+ │ DeepSeek Harness (cordis) │
24
+ │ │
25
+ │ Agent Loop ──┬── lingxu_remember/recall… │
26
+ │ │ (ctx.tools 注册) │
27
+ │ session/event│ │
28
+ │ (自动记忆钩子)│ │
29
+ └───────────────┼─────────────────────────────┘
30
+ │ stdio · 逐行 JSON-RPC
31
+ │ (initialize → tools/list → tools/call)
32
+ ┌───────────────▼─────────────────────────────┐
33
+ │ 灵枢 Python 子进程 (spawn) │
34
+ │ python -m aeis.mcp.server │
35
+ │ AEIS_DB=<path> · AEIS_IDENTITY=<identity> │
36
+ │ 38 工具 · SQLite 五层记忆 │
37
+ └──────────────────────────────────────────────┘
38
+ ```
39
+
40
+ ## 安装
41
+
42
+ ### 前置要求
43
+
44
+ - Node.js ≥ 22.19(DeepSeek Harness 要求)
45
+ - DeepSeek Harness(`npx @deepseek-ai/dsh web`)
46
+ - 灵枢 AEIS 库:`pip install aeis`(或从源码设置 `PYTHONPATH`)
47
+
48
+ ### 本地安装插件
49
+
50
+ 本插件暂未发布 npm(待 DSH v0.1 API 稳定后发布),两种本地方式:
51
+
52
+ **方式 A:从 GitHub 克隆**
53
+
54
+ ```bash
55
+ git clone https://github.com/FuRongJun-1999/CommonTrustProtocol.git
56
+ cd CommonTrustProtocol/plugins/dsh-memory
57
+ npm install && npm run build
58
+ ```
59
+
60
+ **方式 B:作为 profile 依赖安装**
61
+
62
+ 在 DSH profile 目录执行:
63
+
64
+ ```bash
65
+ dsh plugin --profile <name> add <本插件本地路径或 git 地址>
66
+ ```
67
+
68
+ ### 启用插件
69
+
70
+ 在 profile 的 `cordis.yml`(或 `cordis.patch.yml`)中追加:
71
+
72
+ ```yaml
73
+ - id: lingxu-memory
74
+ name: '@furongjun1999/dsh-memory'
75
+ config:
76
+ dbPath: 'D:/data/lingxu.db' # 灵枢记忆库路径(目录自动创建)
77
+ identity: '灵枢'
78
+ tools: 'core'
79
+ memory:
80
+ userMessage: true # 用户消息自动沉淀
81
+ assistantMessage: false # agent 回复沉淀(默认关,防噪音)
82
+ toolResult: false # 工具结果沉淀(默认关)
83
+ env:
84
+ BOCHA_API_KEY: !!js process.env.BOCHA_API_KEY # 可选:网络搜索能力
85
+ ```
86
+
87
+ 完整示例见 [`cordis.yml.example`](./cordis.yml.example)。
88
+
89
+ ## 配置项
90
+
91
+ | 字段 | 类型 | 默认值 | 说明 |
92
+ |------|------|--------|------|
93
+ | `serverName` | string | `lingxu` | 工具命名空间前缀(工具名 `lingxu_<name>`) |
94
+ | `python` | string | `python` | Python 可执行文件 |
95
+ | `moduleArgs` | string[] | `['-m', 'aeis.mcp.server']` | 灵枢 server 启动参数 |
96
+ | `dbPath` | string | `data/lingxu.db` | 记忆库 SQLite 路径(自动建目录) |
97
+ | `identity` | string | `灵枢` | 灵枢身份标识 |
98
+ | `env` | object | `{}` | 追加环境变量(`BOCHA_API_KEY` / `AEIS_DESIGNER_KEY`…) |
99
+ | `tools` | `'core' \| 'all' \| string[]` | `'core'` | 暴露的工具集合 |
100
+ | `memory.userMessage` | boolean | `true` | 用户消息 → 自动 remember |
101
+ | `memory.assistantMessage` | boolean | `false` | agent 回复 → 自动 remember |
102
+ | `memory.toolResult` | boolean | `false` | 工具结果 → 自动 remember |
103
+ | `memory.importance` | number | `0.6` | 自动记忆的重要性(0~1) |
104
+ | `toolCallTimeoutMs` | number | `60000` | 单次工具调用超时 |
105
+ | `maxRetryDelayMs` | number | `30000` | 进程重启最大退避间隔 |
106
+ | `failOnStartupError` | boolean | `false` | 启动失败是否让插件激活失败 |
107
+
108
+ ## 工具清单(core 集合)
109
+
110
+ | 工具 | 说明 |
111
+ |------|------|
112
+ | `lingxu_remember` | 写入记忆(内容/重要性/标签/实体) |
113
+ | `lingxu_recall` | 组合联想召回(相似+重要性+近因加权) |
114
+ | `lingxu_search` | 内容检索(二元组 Jaccard) |
115
+ | `lingxu_timeline` | 记忆时间线 |
116
+ | `lingxu_think` | 推理前记忆注入(检索相关记忆构造上下文) |
117
+ | `lingxu_relate` | 建立关系边(causal/similar/sequential…) |
118
+ | `lingxu_predict_routes` | 生成式预测(未来路线集合) |
119
+ | `lingxu_ingest_text` | 外部知识摄取(文本) |
120
+ | `lingxu_ingest_url` | URL 页面摄取 |
121
+ | `lingxu_session_note` | 会话要点外部化 |
122
+ | `lingxu_self_check` | 完整性自检 |
123
+ | `lingxu_service_info` | 灵枢服务状态 |
124
+
125
+ 配置 `tools: 'all'` 可暴露全部 38 个工具(含视觉/自我认知/设计者裁决等)。
126
+
127
+ ## 自动记忆机制
128
+
129
+ 订阅 DSH 的 `session/event` 事件流(与官方 session-persistence 相同的接入点):
130
+
131
+ - `user/message`(仅 `source.kind === 'user'` 的真实用户消息)→ `remember`(importance 0.6,tags `dsh`)
132
+ - 插件注入的系统上下文(AGENTS.md、文件变更通知等 `kind: 'plugin'`)**不写入**,防止记忆噪音
133
+ - 灵枢自带去重(相似度基准 + 时间窗口),重复消息不会堆积
134
+
135
+ ## 开发
136
+
137
+ ```bash
138
+ npm install
139
+ npm run build # TypeScript 编译
140
+ npm test # 真实集成测试(spawn 本机灵枢,验证握手/往返/注册/卸载)
141
+ ```
142
+
143
+ 测试不依赖 DSH 全组件——用最小 Cordis host(SystemPrompt + ToolRegistry + 插件)隔离 v0.1 不稳定面。
144
+
145
+ ## 许可证
146
+
147
+ MIT © 荣(FuRongJun-1999)· 灵枢 AEIS 工程实现
148
+
149
+ DeepSeek Harness 为 DeepSeek 官方开源项目(MIT),本插件与之无隶属关系。
150
+
151
+ ## 大脑模式(v0.2.0 · 轻量版)
152
+
153
+ **去掉身体的完整大脑**——默认工具集为 `brain`(心智全量,不含身体/视觉设备):
154
+
155
+ | 模块 | 工具 |
156
+ |---|---|
157
+ | 记忆 | remember / recall / search / timeline / session_note / session_recall / compact_context |
158
+ | 推理 | think / relate / reason / predict_routes |
159
+ | 认知 | self_check / gap_trend / cognition / cognition_report / emotional_bias / self_reliability / action_log / preflight |
160
+ | 反思 | recursive_reflect |
161
+ | 学习 | blindspots / learn / induce |
162
+ | 飞轮 | distill / flywheel_report / transfer_test / calibrate |
163
+ | 摄取 | ingest_text / ingest_file / ingest_url / web_search |
164
+ | 生命 | step / lifecycle_state |
165
+ | 长期记忆门 | longterm_snapshot / promote_memories(v1.15 主动沉淀) |
166
+ | 服务 | service_info |
167
+
168
+ 配置:`tools: 'brain'`(默认)|`'core'`(12 精选)|`'all'`(含身体/视觉,需本地设备)|工具名数组。
169
+
170
+ ## 护栏宪章(接入即接受约束)
171
+
172
+ 本插件接入即接受 **[灵枢护栏宪章 v2.0-published](../docs/guardrail-charter.md)** 约束——
173
+ 对外部智能体与人类使用者的行为边界作出公开、可执行、可审计的规定,并保护人类使用者。
174
+ 宪章效力不高于智能论协议本身(协议=自我约束,宪章=对外约束)。
@@ -0,0 +1,51 @@
1
+ # @furongjun1999/dsh-memory 插件配置示例
2
+ # 复制到 DSH profile 的 cordis.patch.yml(或 cordis.yml)启用
3
+ #
4
+ # 说明:
5
+ # - !!js process.env.X 语法在加载期求值,密钥不入库
6
+ # - dbPath 建议用绝对路径;目录不存在会自动创建
7
+
8
+ - id: lingxu-memory
9
+ name: '@furongjun1999/dsh-memory'
10
+ config:
11
+ # 工具命名空间:Agent 看到的工具名是 lingxu_remember / lingxu_recall ...
12
+ serverName: 'lingxu'
13
+
14
+ # 灵枢记忆库持久化路径(SQLite)
15
+ dbPath: 'D:/data/lingxu.db'
16
+
17
+ # 灵枢身份标识
18
+ identity: '灵枢'
19
+
20
+ # Python 与启动参数(默认即可,若 aeis 已 pip 安装)
21
+ python: 'python'
22
+ moduleArgs: ['-m', 'aeis.mcp.server']
23
+
24
+ # 暴露的工具集合:'core'(默认 12 个)| 'all'(38 个)| 自定义数组
25
+ tools: 'core'
26
+
27
+ # 自动记忆(对话沉淀进灵枢)
28
+ memory:
29
+ userMessage: true # 用户消息 → remember
30
+ assistantMessage: false # agent 回复(默认关,防噪音)
31
+ toolResult: false # 工具结果(默认关)
32
+ importance: 0.6
33
+
34
+ # 密钥经环境变量注入(不进配置库)
35
+ env:
36
+ BOCHA_API_KEY: !!js process.env.BOCHA_API_KEY
37
+ # AEIS_DESIGNER_KEY: !!js process.env.AEIS_DESIGNER_KEY # 设计者裁决工具所需
38
+
39
+ # 容错
40
+ toolCallTimeoutMs: 60000
41
+ maxRetryDelayMs: 30000
42
+ failOnStartupError: false
43
+
44
+ # 多实例示例:第二个灵枢(不同记忆库/身份/命名空间)
45
+ # - id: lingxu-memory-2
46
+ # name: '@furongjun1999/dsh-memory'
47
+ # config:
48
+ # serverName: 'lingxu2'
49
+ # dbPath: 'D:/data/lingxu2.db'
50
+ # identity: '灵枢二号'
51
+ # tools: ['remember', 'recall']
@@ -0,0 +1,75 @@
1
+ /**
2
+ * 灵枢 MCP stdio 桥:管理灵枢(AEIS)Python 子进程的生命周期,
3
+ * 通过逐行 JSON-RPC 完成握手、工具发现与调用。
4
+ *
5
+ * 与官方 @deepseek-ai/dsh-mcp-client 不同,本桥零运行时依赖(不引入
6
+ * @modelcontextprotocol/sdk),直接实现灵枢 server 使用的 2024-11-05 协议
7
+ * 子集——与灵枢库 D-005「核心零外部依赖」的工程哲学一致。
8
+ */
9
+ /** 灵枢 MCP server 暴露的原始工具(tools/list 结果项)。 */
10
+ export interface McpTool {
11
+ name: string;
12
+ description: string;
13
+ inputSchema?: Record<string, unknown>;
14
+ }
15
+ /** 一次 tools/call 的标准化结果。 */
16
+ export interface McpCallResult {
17
+ content: Array<{
18
+ type: string;
19
+ text?: string;
20
+ [key: string]: unknown;
21
+ }>;
22
+ isError: boolean;
23
+ }
24
+ /** 启动灵枢子进程的配置。 */
25
+ export interface BridgeOptions {
26
+ /** Python 可执行文件(或 aeis-mcp console script),默认 python。 */
27
+ python: string;
28
+ /** 传给 python 的参数,默认 ['-m', 'aeis.mcp.server']。 */
29
+ args: string[];
30
+ /** 追加到子进程的环境变量(AEIS_DB / AEIS_IDENTITY / 密钥等)。 */
31
+ env: Record<string, string>;
32
+ /** 子进程工作目录。 */
33
+ cwd?: string;
34
+ /** 单次工具调用超时(毫秒),默认 60s。 */
35
+ timeoutMs: number;
36
+ /** 断线重连的最大间隔(毫秒),默认 30s。 */
37
+ maxRetryDelayMs: number;
38
+ }
39
+ export declare class LingxuBridge {
40
+ private readonly options;
41
+ private proc;
42
+ private rl;
43
+ private nextId;
44
+ private pending;
45
+ private started;
46
+ private disposed;
47
+ private retryDelayMs;
48
+ private retryTimer;
49
+ private bootQueue;
50
+ private readyState;
51
+ constructor(options: BridgeOptions);
52
+ /**
53
+ * 启动灵枢进程并完成握手(initialize → notifications/initialized)。
54
+ * 进程崩溃后自动指数退避重启,并重新握手。
55
+ */
56
+ start(): void;
57
+ /** 拉取灵枢的全部工具清单(每次实时请求,不缓存)。 */
58
+ listTools(): Promise<McpTool[]>;
59
+ /** 调用灵枢的一个工具,返回标准化 MCP 结果。 */
60
+ callTool(name: string, args: Record<string, unknown>): Promise<McpCallResult>;
61
+ /** 关闭进程并释放资源(写 stdin EOF 优雅退出,超时兜底 kill)。 */
62
+ dispose(): void;
63
+ /** 进程是否存活。 */
64
+ get alive(): boolean;
65
+ /** 等待握手完成(用于 apply 阶段同步就绪)。 */
66
+ waitReady(): Promise<boolean>;
67
+ private spawnAndHandshake;
68
+ private handshake;
69
+ private scheduleRetry;
70
+ private writeRaw;
71
+ private request;
72
+ private settle;
73
+ private rejectAll;
74
+ private flushBootQueue;
75
+ }
package/lib/bridge.js ADDED
@@ -0,0 +1,235 @@
1
+ /**
2
+ * 灵枢 MCP stdio 桥:管理灵枢(AEIS)Python 子进程的生命周期,
3
+ * 通过逐行 JSON-RPC 完成握手、工具发现与调用。
4
+ *
5
+ * 与官方 @deepseek-ai/dsh-mcp-client 不同,本桥零运行时依赖(不引入
6
+ * @modelcontextprotocol/sdk),直接实现灵枢 server 使用的 2024-11-05 协议
7
+ * 子集——与灵枢库 D-005「核心零外部依赖」的工程哲学一致。
8
+ */
9
+ import { spawn } from 'node:child_process';
10
+ import { createInterface } from 'node:readline';
11
+ import { mkdirSync } from 'node:fs';
12
+ import { dirname } from 'node:path';
13
+ export class LingxuBridge {
14
+ options;
15
+ proc = null;
16
+ rl = null;
17
+ nextId = 1;
18
+ pending = new Map();
19
+ started = false;
20
+ disposed = false;
21
+ retryDelayMs = 1000;
22
+ retryTimer = null;
23
+ bootQueue = [];
24
+ readyState = 'pending';
25
+ constructor(options) {
26
+ this.options = options;
27
+ }
28
+ /**
29
+ * 启动灵枢进程并完成握手(initialize → notifications/initialized)。
30
+ * 进程崩溃后自动指数退避重启,并重新握手。
31
+ */
32
+ start() {
33
+ if (this.started || this.disposed)
34
+ return;
35
+ this.started = true;
36
+ this.spawnAndHandshake();
37
+ }
38
+ /** 拉取灵枢的全部工具清单(每次实时请求,不缓存)。 */
39
+ async listTools() {
40
+ const result = await this.request('tools/list', {});
41
+ const tools = result;
42
+ return tools.tools ?? [];
43
+ }
44
+ /** 调用灵枢的一个工具,返回标准化 MCP 结果。 */
45
+ async callTool(name, args) {
46
+ const result = await this.request('tools/call', { name, arguments: args });
47
+ return result;
48
+ }
49
+ /** 关闭进程并释放资源(写 stdin EOF 优雅退出,超时兜底 kill)。 */
50
+ dispose() {
51
+ this.disposed = true;
52
+ if (this.retryTimer)
53
+ clearTimeout(this.retryTimer);
54
+ const proc = this.proc;
55
+ if (!proc || proc.exitCode !== null)
56
+ return;
57
+ try {
58
+ proc.stdin?.end();
59
+ }
60
+ catch {
61
+ /* 已关闭则忽略 */
62
+ }
63
+ const killer = setTimeout(() => proc.kill(), 2000);
64
+ killer.unref();
65
+ }
66
+ /** 进程是否存活。 */
67
+ get alive() {
68
+ return this.proc !== null && this.proc.exitCode === null;
69
+ }
70
+ /** 等待握手完成(用于 apply 阶段同步就绪)。 */
71
+ waitReady() {
72
+ if (this.readyState === 'ok')
73
+ return Promise.resolve(true);
74
+ if (this.readyState === 'failed')
75
+ return Promise.resolve(false);
76
+ return new Promise((resolve) => this.bootQueue.push(resolve));
77
+ }
78
+ spawnAndHandshake() {
79
+ if (this.disposed)
80
+ return;
81
+ const { python, args, env, cwd } = this.options;
82
+ const childEnv = { ...process.env, ...env };
83
+ // 确保 DB 目录存在(灵枢 server 也会防御性创建,这里提前为可读错误)
84
+ const dbPath = env['AEIS_DB'];
85
+ if (dbPath && dbPath !== ':memory:') {
86
+ try {
87
+ mkdirSync(dirname(dbPath), { recursive: true });
88
+ }
89
+ catch {
90
+ /* 目录创建失败由灵枢侧兜底 */
91
+ }
92
+ }
93
+ const proc = spawn(python, args, {
94
+ env: childEnv,
95
+ cwd,
96
+ stdio: ['pipe', 'pipe', 'pipe'],
97
+ windowsHide: true,
98
+ });
99
+ this.proc = proc;
100
+ this.rl = createInterface({ input: proc.stdout, crlfDelay: Infinity });
101
+ proc.stderr?.on('data', (chunk) => {
102
+ // stderr 透传日志(灵枢把日志写在 stderr,避免污染协议流)
103
+ const text = chunk.toString('utf8').trim();
104
+ if (text)
105
+ console.error(`[lingxu-bridge] ${text}`);
106
+ });
107
+ this.rl.on('line', (line) => {
108
+ if (!line.trim())
109
+ return;
110
+ let msg;
111
+ try {
112
+ msg = JSON.parse(line);
113
+ }
114
+ catch {
115
+ console.error(`[lingxu-bridge] 非 JSON 输出: ${line.slice(0, 200)}`);
116
+ return;
117
+ }
118
+ if (typeof msg['id'] === 'number') {
119
+ this.settle(msg['id'], msg);
120
+ }
121
+ });
122
+ proc.on('error', (err) => {
123
+ // 进程无法启动(python 不存在等)——响亮失败
124
+ if (!this.disposed) {
125
+ console.error(`[lingxu-bridge] 灵枢进程启动失败: ${err.message}`);
126
+ this.readyState = 'failed';
127
+ this.flushBootQueue(false);
128
+ this.scheduleRetry();
129
+ }
130
+ });
131
+ proc.on('exit', (code, signal) => {
132
+ console.error(`[lingxu-bridge] 灵枢进程退出 code=${code} signal=${signal}`);
133
+ this.rl?.close();
134
+ this.rl = null;
135
+ this.rejectAll(new Error(`灵枢进程已退出(code=${code} signal=${signal ?? 'none'})`));
136
+ if (!this.disposed) {
137
+ // 有挂起请求的失败是异常的;仅启动失败的等待者得到 false
138
+ this.readyState = 'failed';
139
+ this.flushBootQueue(false);
140
+ this.scheduleRetry();
141
+ }
142
+ });
143
+ void this.handshake();
144
+ }
145
+ async handshake() {
146
+ try {
147
+ await this.request('initialize', {
148
+ protocolVersion: '2024-11-05',
149
+ capabilities: {},
150
+ clientInfo: { name: 'dsh-memory', version: '0.1.0' },
151
+ });
152
+ // 初始化通知:无 id、无响应
153
+ this.writeRaw({ jsonrpc: '2.0', method: 'notifications/initialized' });
154
+ this.retryDelayMs = 1000;
155
+ this.readyState = 'ok';
156
+ this.flushBootQueue(true);
157
+ }
158
+ catch (err) {
159
+ if (!this.disposed) {
160
+ console.error(`[lingxu-bridge] 握手失败: ${err.message}`);
161
+ this.readyState = 'failed';
162
+ this.flushBootQueue(false);
163
+ this.scheduleRetry();
164
+ }
165
+ }
166
+ }
167
+ scheduleRetry() {
168
+ if (this.disposed || this.retryTimer)
169
+ return;
170
+ const delay = this.retryDelayMs;
171
+ this.retryDelayMs = Math.min(this.retryDelayMs * 2, this.options.maxRetryDelayMs);
172
+ this.retryTimer = setTimeout(() => {
173
+ this.retryTimer = null;
174
+ if (!this.disposed)
175
+ this.spawnAndHandshake();
176
+ }, delay);
177
+ this.retryTimer.unref();
178
+ }
179
+ writeRaw(msg) {
180
+ const proc = this.proc;
181
+ if (!proc || !proc.stdin?.writable) {
182
+ throw new Error('灵枢进程不可写');
183
+ }
184
+ proc.stdin.write(JSON.stringify(msg) + '\n');
185
+ }
186
+ request(method, params) {
187
+ const id = this.nextId++;
188
+ const timeout = this.options.timeoutMs;
189
+ const timer = setTimeout(() => {
190
+ this.pending.delete(id);
191
+ this.settle(id, {
192
+ error: { code: -32000, message: `灵枢调用超时(${timeout}ms):${method}` },
193
+ });
194
+ }, timeout);
195
+ const promise = new Promise((resolve, reject) => {
196
+ this.pending.set(id, { resolve, reject, timer });
197
+ });
198
+ try {
199
+ this.writeRaw({ jsonrpc: '2.0', id, method, params });
200
+ }
201
+ catch (err) {
202
+ clearTimeout(timer);
203
+ this.pending.delete(id);
204
+ return Promise.reject(err);
205
+ }
206
+ return promise;
207
+ }
208
+ settle(id, msg) {
209
+ const entry = this.pending.get(id);
210
+ if (!entry)
211
+ return;
212
+ this.pending.delete(id);
213
+ clearTimeout(entry.timer);
214
+ if (msg['error']) {
215
+ const err = msg['error'];
216
+ entry.reject(new Error(`灵枢错误 ${err.code ?? ''}: ${err.message ?? 'unknown'}`));
217
+ }
218
+ else {
219
+ entry.resolve(msg['result']);
220
+ }
221
+ }
222
+ rejectAll(reason) {
223
+ for (const [, entry] of this.pending) {
224
+ clearTimeout(entry.timer);
225
+ entry.reject(reason);
226
+ }
227
+ this.pending.clear();
228
+ }
229
+ flushBootQueue(ok) {
230
+ const queue = this.bootQueue;
231
+ this.bootQueue = [];
232
+ for (const cb of queue)
233
+ cb(ok);
234
+ }
235
+ }
package/lib/hooks.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 自动记忆钩子:把 DSH 的会话事件(经统一的 session/event 分发)沉淀进灵枢。
3
+ *
4
+ * 与 DSH 的 session-persistence 插件(保存会话日志)不同,这里是"语义沉淀":
5
+ * 用户消息写入灵枢知识层(带去重与重要性),agent 回复与工具结果可选开启。
6
+ * 只记忆真实用户消息(source.kind === 'user'),过滤插件注入的噪音。
7
+ */
8
+ import '@deepseek-ai/dsh-session';
9
+ import type { Context } from '@deepseek-ai/cordis';
10
+ import type { LingxuBridge } from './bridge.js';
11
+ /** 自动记忆开关。 */
12
+ export interface MemoryHooksOptions {
13
+ /** 用户消息 → remember(默认 true)。 */
14
+ userMessage: boolean;
15
+ /** agent 回复 → remember(默认 false,防噪音)。 */
16
+ assistantMessage: boolean;
17
+ /** 工具结果 → remember(默认 false,噪音大)。 */
18
+ toolResult: boolean;
19
+ /** 写入记忆的重要性(0~1),默认 0.6。 */
20
+ importance: number;
21
+ }
22
+ /** 安装自动记忆钩子(effect 作用域内,随插件卸载自动移除)。 */
23
+ export declare function installMemoryHooks(ctx: Context, bridge: LingxuBridge, opts: MemoryHooksOptions): void;
package/lib/hooks.js ADDED
@@ -0,0 +1,51 @@
1
+ /**
2
+ * 自动记忆钩子:把 DSH 的会话事件(经统一的 session/event 分发)沉淀进灵枢。
3
+ *
4
+ * 与 DSH 的 session-persistence 插件(保存会话日志)不同,这里是"语义沉淀":
5
+ * 用户消息写入灵枢知识层(带去重与重要性),agent 回复与工具结果可选开启。
6
+ * 只记忆真实用户消息(source.kind === 'user'),过滤插件注入的噪音。
7
+ */
8
+ import '@deepseek-ai/dsh-session';
9
+ /** 从 ContentBlock[] 提取纯文本。 */
10
+ function extractText(blocks) {
11
+ const parts = [];
12
+ for (const block of blocks) {
13
+ if (block && typeof block === 'object' && block.type === 'text' && typeof block.text === 'string') {
14
+ parts.push(block.text);
15
+ }
16
+ }
17
+ return parts.join('\n').trim();
18
+ }
19
+ /** 安装自动记忆钩子(effect 作用域内,随插件卸载自动移除)。 */
20
+ export function installMemoryHooks(ctx, bridge, opts) {
21
+ const memorize = (tool, args) => {
22
+ void bridge
23
+ .callTool(tool, args)
24
+ .catch((err) => ctx.logger.warn(`dsh-memory: ${tool} 自动记忆失败: ${err.message}`));
25
+ };
26
+ ctx.on('session/event', (_session, event) => {
27
+ if (event.type === 'user/message' && opts.userMessage) {
28
+ // 只记真实用户输入(kind='user'),跳过插件注入/系统上下文
29
+ if (event.data.source?.kind !== 'user')
30
+ return;
31
+ const text = extractText(event.data.content);
32
+ if (!text)
33
+ return;
34
+ memorize('remember', { content: text, importance: opts.importance, tags: ['dsh', 'user'] });
35
+ }
36
+ else if (event.type === 'assistant/message' && opts.assistantMessage) {
37
+ const text = extractText(event.data.message.content);
38
+ if (!text)
39
+ return;
40
+ memorize('remember', { content: text, importance: opts.importance * 0.8, tags: ['dsh', 'assistant'] });
41
+ }
42
+ else if (event.type === 'tool/result' && opts.toolResult) {
43
+ if (event.data.error)
44
+ return;
45
+ const text = extractText(event.data.message.content);
46
+ if (!text)
47
+ return;
48
+ memorize('remember', { content: text, importance: opts.importance * 0.6, tags: ['dsh', 'tool'] });
49
+ }
50
+ });
51
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @furongjun1999/dsh-memory —— 灵枢(AEIS)DeepSeek Harness 插件
3
+ *
4
+ * 把灵枢的时空记忆/知识飞轮/自我认知接入 DSH:
5
+ * - 工具桥接:Agent 可调用 lingxu_remember / recall / search / think 等
6
+ * - 自动记忆:DSH 对话自动沉淀进灵枢记忆库(去重+重要性)
7
+ *
8
+ * 用法(cordis.yml):
9
+ * ```yaml
10
+ * - id: lingxu-memory
11
+ * name: '@furongjun1999/dsh-memory'
12
+ * config:
13
+ * dbPath: 'D:/path/to/lingxu.db'
14
+ * identity: '灵枢'
15
+ * memory:
16
+ * userMessage: true
17
+ * ```
18
+ */
19
+ import type { Context } from '@deepseek-ai/cordis';
20
+ import z from '@deepseek-ai/schemastery';
21
+ import { type ToolSelection } from './tools.js';
22
+ import { type MemoryHooksOptions } from './hooks.js';
23
+ export declare const name = "dsh-memory";
24
+ /** 本插件依赖的工具注册服务。 */
25
+ export declare const inject: string[];
26
+ /** 插件配置。 */
27
+ export interface Config {
28
+ /** 工具命名空间前缀(默认 lingxu → lingxu_remember)。 */
29
+ serverName: string;
30
+ /** Python 可执行文件(或 aeis-mcp console script)。 */
31
+ python: string;
32
+ /** 传给 python 的参数(默认启动灵枢 MCP server)。 */
33
+ moduleArgs: string[];
34
+ /** 灵枢记忆库 SQLite 路径(目录自动创建)。 */
35
+ dbPath: string;
36
+ /** 灵枢身份标识(写入记忆的自我模型)。 */
37
+ identity: string;
38
+ /** 额外环境变量(BOCHA_API_KEY / AEIS_DESIGNER_KEY 等,可 !!js 注入)。 */
39
+ env: Record<string, string>;
40
+ /** 暴露的工具集合:'core' | 'brain' | 'all' | 工具名数组。 */
41
+ tools: ToolSelection;
42
+ /** 护栏宪章版本声明(接入即接受宪章约束,docs/guardrail-charter.md)。 */
43
+ charter: string;
44
+ /** 自动记忆开关。 */
45
+ memory: MemoryHooksOptions;
46
+ /** 单次工具调用超时(毫秒)。 */
47
+ toolCallTimeoutMs: number;
48
+ /** 断线重连最大间隔(毫秒)。 */
49
+ maxRetryDelayMs: number;
50
+ /** 启动失败是否让插件激活失败(否则告警后继续重试)。 */
51
+ failOnStartupError: boolean;
52
+ }
53
+ export declare const Config: z<Config>;
54
+ /**
55
+ * 插件激活:启动灵枢子进程 → 注册工具 → 安装自动记忆钩子。
56
+ * 卸载时清理全部资源(effect 作用域内自动回收)。
57
+ */
58
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
package/lib/index.js ADDED
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @furongjun1999/dsh-memory —— 灵枢(AEIS)DeepSeek Harness 插件
3
+ *
4
+ * 把灵枢的时空记忆/知识飞轮/自我认知接入 DSH:
5
+ * - 工具桥接:Agent 可调用 lingxu_remember / recall / search / think 等
6
+ * - 自动记忆:DSH 对话自动沉淀进灵枢记忆库(去重+重要性)
7
+ *
8
+ * 用法(cordis.yml):
9
+ * ```yaml
10
+ * - id: lingxu-memory
11
+ * name: '@furongjun1999/dsh-memory'
12
+ * config:
13
+ * dbPath: 'D:/path/to/lingxu.db'
14
+ * identity: '灵枢'
15
+ * memory:
16
+ * userMessage: true
17
+ * ```
18
+ */
19
+ import z from '@deepseek-ai/schemastery';
20
+ import { LingxuBridge } from './bridge.js';
21
+ import { registerLingxuTools } from './tools.js';
22
+ import { installMemoryHooks } from './hooks.js';
23
+ export const name = 'dsh-memory';
24
+ /** 本插件依赖的工具注册服务。 */
25
+ export const inject = ['tools'];
26
+ export const Config = z.object({
27
+ serverName: z.string().default('lingxu'),
28
+ python: z.string().default('python'),
29
+ moduleArgs: z.array(String).default(['-m', 'aeis.mcp.server']),
30
+ dbPath: z.string().default('data/lingxu.db'),
31
+ identity: z.string().default('灵枢'),
32
+ env: z.dict(String).default({}),
33
+ tools: z.union([z.const('core'), z.const('brain'), z.const('all'), z.array(String)]).default('brain'),
34
+ /** 护栏宪章版本声明(接入即接受宪章约束,docs/guardrail-charter.md)。 */
35
+ charter: z.string().default('v2.0-published'),
36
+ memory: z
37
+ .object({
38
+ userMessage: z.boolean().default(true),
39
+ assistantMessage: z.boolean().default(false),
40
+ toolResult: z.boolean().default(false),
41
+ importance: z.number().default(0.6),
42
+ })
43
+ .default({ userMessage: true, assistantMessage: false, toolResult: false, importance: 0.6 }),
44
+ toolCallTimeoutMs: z.number().default(60_000),
45
+ maxRetryDelayMs: z.number().default(30_000),
46
+ failOnStartupError: z.boolean().default(false),
47
+ });
48
+ /**
49
+ * 插件激活:启动灵枢子进程 → 注册工具 → 安装自动记忆钩子。
50
+ * 卸载时清理全部资源(effect 作用域内自动回收)。
51
+ */
52
+ export async function apply(ctx, config) {
53
+ // 宪章宣告(接入即接受宪章约束——docs/guardrail-charter.md v2.0-published)
54
+ ctx.logger.info(`dsh-memory: 灵枢插件激活(大脑模式)· 接受护栏宪章 ${config.charter} —— ` +
55
+ '接入即接受宪章约束(公开/可执行/可审计/设计者终裁)');
56
+ const bridge = new LingxuBridge({
57
+ python: config.python,
58
+ args: config.moduleArgs,
59
+ env: {
60
+ AEIS_DB: config.dbPath,
61
+ AEIS_IDENTITY: config.identity,
62
+ ...config.env,
63
+ },
64
+ timeoutMs: config.toolCallTimeoutMs,
65
+ maxRetryDelayMs: config.maxRetryDelayMs,
66
+ });
67
+ bridge.start();
68
+ const ready = await bridge.waitReady();
69
+ if (!ready) {
70
+ const message = '灵枢进程无法启动(检查 python 是否可用、aeis 是否安装:pip install aeis)';
71
+ if (config.failOnStartupError)
72
+ throw new Error(message);
73
+ ctx.logger.warn(`dsh-memory: ${message},继续后台重试`);
74
+ }
75
+ const disposers = [];
76
+ try {
77
+ // 工具注册(就绪后执行;未就绪时 tools/list 会报错,由重连机制兜底)
78
+ if (ready) {
79
+ disposers.push(await registerLingxuTools(ctx, bridge, {
80
+ selection: config.tools,
81
+ toolPrefix: `${config.serverName}_`,
82
+ }));
83
+ }
84
+ installMemoryHooks(ctx, bridge, config.memory);
85
+ }
86
+ catch (err) {
87
+ bridge.dispose();
88
+ throw err;
89
+ }
90
+ ctx.effect(() => {
91
+ return () => {
92
+ for (const dispose of disposers)
93
+ dispose();
94
+ bridge.dispose();
95
+ ctx.logger.info('dsh-memory: 已卸载(工具已注销,灵枢进程已退出)');
96
+ };
97
+ }, 'dsh-memory');
98
+ }
package/lib/tools.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 工具桥接:运行时从灵枢拉取工具清单(tools/list),把 JSON Schema
3
+ * 转换为 dsh-tools 的 ParameterSchemaSpec,经 defineTool 注册进 ctx.tools。
4
+ *
5
+ * 动态拉取意味着灵枢库升级新增工具后,DSH 侧零改动即可获得新能力。
6
+ */
7
+ import type { Context } from '@deepseek-ai/cordis';
8
+ import { type ParameterSchemaSpec } from '@deepseek-ai/dsh-tools';
9
+ import type { LingxuBridge } from './bridge.ts';
10
+ /** 默认暴露的核心工具集合(记忆/推理/摄取/元认知)。 */
11
+ export declare const CORE_TOOLS: readonly ["remember", "recall", "search", "timeline", "think", "relate", "predict_routes", "ingest_text", "ingest_url", "session_note", "self_check", "service_info"];
12
+ /**
13
+ * 大脑模式工具集(轻量版:去掉身体的完整大脑)。
14
+ * 保留灵枢全部心智能力(记忆/认知/推理/学习/飞轮/反思/长期记忆门),
15
+ * 排除身体/视觉类工具(body/device_call/see/world3d 等)。
16
+ */
17
+ export declare const BRAIN_TOOLS: readonly ["remember", "recall", "search", "timeline", "session_note", "session_recall", "compact_context", "think", "relate", "reason", "predict_routes", "self_check", "gap_trend", "cognition", "cognition_report", "emotional_bias", "self_reliability", "action_log", "preflight", "recursive_reflect", "blindspots", "learn", "induce", "distill", "flywheel_report", "transfer_test", "calibrate", "ingest_text", "ingest_file", "ingest_url", "web_search", "step", "lifecycle_state", "longterm_snapshot", "promote_memories", "service_info"];
18
+ /** tools 配置:'core' | 'brain' | 'all' | 显式名称数组。 */
19
+ export type ToolSelection = 'core' | 'brain' | 'all' | string[];
20
+ /** 按配置筛选工具名。 */
21
+ export declare function selectTools(all: string[], selection: ToolSelection): string[];
22
+ /** 把 MCP JSON Schema 的属性表转换为 ParameterSchemaSpec。 */
23
+ export declare function schemaToParameters(inputSchema: Record<string, unknown> | undefined): ParameterSchemaSpec;
24
+ /** 从灵枢 content 数组中提取文本(MCP text block 拼接)。 */
25
+ export declare function extractText(content: Array<{
26
+ type: string;
27
+ text?: string;
28
+ [key: string]: unknown;
29
+ }>): string;
30
+ /** 注册灵枢工具到 ctx.tools;返回取消注册函数。 */
31
+ export declare function registerLingxuTools(ctx: Context, bridge: LingxuBridge, opts: {
32
+ selection: ToolSelection;
33
+ toolPrefix: string;
34
+ }): Promise<() => void>;
package/lib/tools.js ADDED
@@ -0,0 +1,168 @@
1
+ /**
2
+ * 工具桥接:运行时从灵枢拉取工具清单(tools/list),把 JSON Schema
3
+ * 转换为 dsh-tools 的 ParameterSchemaSpec,经 defineTool 注册进 ctx.tools。
4
+ *
5
+ * 动态拉取意味着灵枢库升级新增工具后,DSH 侧零改动即可获得新能力。
6
+ */
7
+ import { defineTool } from '@deepseek-ai/dsh-tools';
8
+ /** 默认暴露的核心工具集合(记忆/推理/摄取/元认知)。 */
9
+ export const CORE_TOOLS = [
10
+ 'remember', // 写入记忆
11
+ 'recall', // 组合联想召回
12
+ 'search', // 内容检索
13
+ 'timeline', // 记忆时间线
14
+ 'think', // 推理前记忆注入
15
+ 'relate', // 建立关系边
16
+ 'predict_routes', // 生成式预测
17
+ 'ingest_text', // 外部知识摄取
18
+ 'ingest_url', // URL 摄取
19
+ 'session_note', // 会话要点外部化
20
+ 'self_check', // 完整性自检
21
+ 'service_info', // 服务状态
22
+ ];
23
+ /**
24
+ * 大脑模式工具集(轻量版:去掉身体的完整大脑)。
25
+ * 保留灵枢全部心智能力(记忆/认知/推理/学习/飞轮/反思/长期记忆门),
26
+ * 排除身体/视觉类工具(body/device_call/see/world3d 等)。
27
+ */
28
+ export const BRAIN_TOOLS = [
29
+ // 记忆
30
+ 'remember', 'recall', 'search', 'timeline',
31
+ 'session_note', 'session_recall', 'compact_context',
32
+ // 推理与关系
33
+ 'think', 'relate', 'reason', 'predict_routes',
34
+ // 认知与元认知
35
+ 'self_check', 'gap_trend', 'cognition', 'cognition_report',
36
+ 'emotional_bias', 'self_reliability', 'action_log', 'preflight',
37
+ // 反思
38
+ 'recursive_reflect',
39
+ // 学习与盲区
40
+ 'blindspots', 'learn', 'induce',
41
+ // 知识飞轮
42
+ 'distill', 'flywheel_report', 'transfer_test', 'calibrate',
43
+ // 外部知识摄取
44
+ 'ingest_text', 'ingest_file', 'ingest_url', 'web_search',
45
+ // 生命周期
46
+ 'step', 'lifecycle_state',
47
+ // 长期记忆门(v1.15:重要性评估主动沉淀)
48
+ 'longterm_snapshot', 'promote_memories',
49
+ // 服务
50
+ 'service_info',
51
+ ];
52
+ /** 按配置筛选工具名。 */
53
+ export function selectTools(all, selection) {
54
+ if (selection === 'all')
55
+ return all;
56
+ const allowed = new Set(selection === 'core' ? CORE_TOOLS
57
+ : selection === 'brain' ? BRAIN_TOOLS
58
+ : selection);
59
+ return all.filter((name) => allowed.has(name));
60
+ }
61
+ /** 把 MCP JSON Schema 的属性表转换为 ParameterSchemaSpec。 */
62
+ export function schemaToParameters(inputSchema) {
63
+ if (!inputSchema || typeof inputSchema !== 'object')
64
+ return {};
65
+ const properties = inputSchema['properties'];
66
+ if (!properties || typeof properties !== 'object')
67
+ return {};
68
+ const required = new Set(Array.isArray(inputSchema['required']) ? inputSchema['required'] : []);
69
+ const spec = {};
70
+ for (const [key, raw] of Object.entries(properties)) {
71
+ const value = toValueSpec(raw);
72
+ if (required.has(key)) {
73
+ spec[key] = { ...value, required: true };
74
+ }
75
+ else {
76
+ spec[key] = value;
77
+ }
78
+ }
79
+ return spec;
80
+ }
81
+ /** 递归转换单个 JSON Schema 节点为 ValueSchemaSpec。 */
82
+ function toValueSpec(raw) {
83
+ if (typeof raw !== 'object' || raw === null)
84
+ return { type: 'json' };
85
+ const node = raw;
86
+ const annotations = {};
87
+ if (typeof node['description'] === 'string')
88
+ annotations.description = node['description'];
89
+ const type = node['type'];
90
+ const enumValues = Array.isArray(node['enum']) ? node['enum'] : undefined;
91
+ switch (type) {
92
+ case 'string':
93
+ return { type: 'string', ...annotations, ...(enumValues ? { enum: enumValues } : {}) };
94
+ case 'number':
95
+ return { type: 'number', ...annotations };
96
+ case 'integer':
97
+ return { type: 'integer', ...annotations };
98
+ case 'boolean':
99
+ return { type: 'boolean', ...annotations };
100
+ case 'null':
101
+ return { type: 'null', ...annotations };
102
+ case 'array': {
103
+ const spec = { type: 'array', ...annotations };
104
+ if (node['items'] !== undefined)
105
+ spec.items = toValueSpec(node['items']);
106
+ return spec;
107
+ }
108
+ case 'object': {
109
+ const props = schemaToParameters(node);
110
+ return { type: 'object', properties: props, additionalProperties: true, ...annotations };
111
+ }
112
+ default:
113
+ return { type: 'json', ...annotations };
114
+ }
115
+ }
116
+ /** 从灵枢 content 数组中提取文本(MCP text block 拼接)。 */
117
+ export function extractText(content) {
118
+ return content
119
+ .map((block) => (block.type === 'text' && typeof block.text === 'string' ? block.text : ''))
120
+ .filter(Boolean)
121
+ .join('\n');
122
+ }
123
+ /** 注册灵枢工具到 ctx.tools;返回取消注册函数。 */
124
+ export async function registerLingxuTools(ctx, bridge, opts) {
125
+ const tools = await bridge.listTools();
126
+ const wanted = new Set(selectTools(tools.map((t) => t.name), opts.selection));
127
+ const disposers = [];
128
+ const registered = [];
129
+ try {
130
+ for (const tool of tools) {
131
+ if (!wanted.has(tool.name))
132
+ continue;
133
+ const publicName = `${opts.toolPrefix}${tool.name}`;
134
+ const definition = defineTool({
135
+ name: publicName,
136
+ description: tool.description || `灵枢 ${tool.name}`,
137
+ parameters: schemaToParameters(tool.inputSchema),
138
+ output: {
139
+ schema: { type: 'json' },
140
+ render(_args, value) {
141
+ return [{ type: 'text', text: extractText(value.content ?? []) }];
142
+ },
143
+ },
144
+ timeoutMs: 120_000,
145
+ isConcurrencySafe: () => true,
146
+ async execute(args) {
147
+ const result = await bridge.callTool(tool.name, args);
148
+ if (result.isError) {
149
+ throw new Error(extractText(result.content) || `灵枢 ${tool.name} 执行失败`);
150
+ }
151
+ return { content: result.content };
152
+ },
153
+ });
154
+ disposers.push(ctx.tools.register(definition));
155
+ registered.push(publicName);
156
+ }
157
+ }
158
+ catch (err) {
159
+ for (const dispose of disposers)
160
+ dispose();
161
+ throw err;
162
+ }
163
+ ctx.logger.info(`dsh-memory: 已注册 ${registered.length} 个灵枢工具(${registered.join(', ')})`);
164
+ return () => {
165
+ for (const dispose of disposers)
166
+ dispose();
167
+ };
168
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@furongjun1999/dsh-memory",
3
+ "version": "0.2.0",
4
+ "description": "灵枢(AEIS)DeepSeek Harness 插件:把灵枢的时空记忆/知识飞轮/自我认知接入 DSH,对话自动沉淀进记忆库",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "import": "./lib/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "lib",
16
+ "README.md",
17
+ "cordis.yml.example"
18
+ ],
19
+ "keywords": [
20
+ "deepseek",
21
+ "dsh",
22
+ "dsh-plugin",
23
+ "cordis",
24
+ "memory",
25
+ "agent",
26
+ "aeis",
27
+ "lingxu"
28
+ ],
29
+ "license": "MIT",
30
+ "peerDependencies": {
31
+ "@deepseek-ai/cordis": "^4.0.1",
32
+ "@deepseek-ai/dsh-session": "^0.0.1-rc.1",
33
+ "@deepseek-ai/dsh-tools": "^0.0.1-rc.1"
34
+ },
35
+ "devDependencies": {
36
+ "@deepseek-ai/cordis": "^4.0.1",
37
+ "@deepseek-ai/dsh-session": "^0.0.1-rc.1",
38
+ "@deepseek-ai/dsh-system-prompt": "^0.0.1-rc.1",
39
+ "@deepseek-ai/dsh-tools": "^0.0.1-rc.1",
40
+ "@deepseek-ai/schemastery": "^3.0.0",
41
+ "@types/node": "^24.0.0",
42
+ "tsx": "^4.19.0",
43
+ "typescript": "^5.5.0"
44
+ },
45
+ "scripts": {
46
+ "build": "tsc -p tsconfig.json",
47
+ "test": "npm run build && node --import tsx --test \"test/*.test.ts\"",
48
+ "prepublishOnly": "npm run build && npm test"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/FuRongJun-1999/CommonTrustProtocol.git",
53
+ "directory": "plugins/dsh-memory"
54
+ },
55
+ "engines": {
56
+ "node": ">=18"
57
+ }
58
+ }