@cup319/mmpl 2.7.0 → 2.8.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 +26 -2
- package/dist/index.js +142 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## 核心特性
|
|
9
9
|
|
|
10
|
-
- **
|
|
10
|
+
- **9 个精简工具**:write、search、list、manage、evolve、compress、palace、symbol、stats
|
|
11
11
|
- **模型自动下载**:首次启动自动从 HuggingFace 下载 ONNX 模型(默认 all-MiniLM-L6-v2,90MB,384维)
|
|
12
12
|
- **跨平台支持**:Windows + Linux,自动适配路径和信号处理
|
|
13
13
|
- **记忆生命周期**:Active → Infrequent → Archived → Permanent(含衰减、强化、SM-2 间隔复习)
|
|
@@ -140,7 +140,7 @@ curl http://127.0.0.1:7680/
|
|
|
140
140
|
{ "type": "summary" }
|
|
141
141
|
```
|
|
142
142
|
|
|
143
|
-
到这里你已经跑通了完整闭环。
|
|
143
|
+
到这里你已经跑通了完整闭环。9 个工具的完整说明见下文「工具一览」。
|
|
144
144
|
|
|
145
145
|
> **常驻保活**:HTTP server 自身不会自我守护。Windows 推荐 `nssm install MMPL node D:\path\to\dist\index.js`,Linux/macOS 推荐 `systemd` 或 `pm2 start dist/index.js --name mmpl`。
|
|
146
146
|
|
|
@@ -181,6 +181,29 @@ HTTP server 启动后不自我守护,靠外部保活:
|
|
|
181
181
|
|
|
182
182
|
> server 默认只绑 `127.0.0.1`(本机访问)。多 client 共享时**不要**起第二个 server 进程——DuckDB 文件是单进程独占的,第二个进程会启动失败;多个 client 都连同一个 HTTP URL 即可。
|
|
183
183
|
|
|
184
|
+
### ZCode 集成:常驻 + 无弹窗(开箱即用)
|
|
185
|
+
|
|
186
|
+
如果你在 ZCode 里用 mmpl,推荐用仓库自带的部署示例 [`examples/zcode-deploy/`](./examples/zcode-deploy/)。它通过 SessionStart/Stop hook 实现:
|
|
187
|
+
|
|
188
|
+
- **常驻运行**:server 启动一次后一直留在后台,切换 ZCode session 不重启(避免每次等 5–10s ONNX 加载)
|
|
189
|
+
- **无 node.exe 黑窗**:所有 `spawn` 配 `windowsHide: true`(修复了 Windows 上启动时弹 `C:\...\node.exe` 窗口的问题)
|
|
190
|
+
- **日志落盘**:server 的 stdout/stderr 重定向到 `.mmpl-server.log`,排查启动失败有据可查
|
|
191
|
+
|
|
192
|
+
一键安装:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# 1. 准备部署目录
|
|
196
|
+
mkdir D:\mmpl-deploy && cd D:\mmpl-deploy
|
|
197
|
+
npm init -y && npm install @cup319/mmpl
|
|
198
|
+
# 2. 复制示例脚本
|
|
199
|
+
cp /path/to/examples/zcode-deploy/*.mjs .
|
|
200
|
+
# 3. 按示例 README 配置 ~/.zcode/cli/config.json 的 hook
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
完整步骤、配置示例、运行机制、弹窗 bug 修复历史详见 [`examples/zcode-deploy/README.md`](./examples/zcode-deploy/README.md)。
|
|
204
|
+
|
|
205
|
+
> **澄清**:`@cup319/mmpl` npm 包本身不 spawn 子进程,**不存在弹窗问题**。弹窗只发生在用 `start-mmpl.mjs` 包装启动时(该脚本 spawn 子进程的方式在 Windows 上需要 `windowsHide`),示例脚本已修复。
|
|
206
|
+
|
|
184
207
|
### 遗留:stdio 模式
|
|
185
208
|
|
|
186
209
|
v2.5.1 之前默认走 stdio,每个 client 各 spawn 一个进程。该模式已在 v2.5.1 移除(多 client 场景下 DuckDB 文件锁无法解决)。如确需单 client stdio,可 git checkout v2.4.4 标签。
|
|
@@ -208,6 +231,7 @@ v2.5.1 之前默认走 stdio,每个 client 各 spawn 一个进程。该模式
|
|
|
208
231
|
|------|------|
|
|
209
232
|
| `memory_write` | 写入记忆(encode 编码 + capture 捕获) |
|
|
210
233
|
| `memory_search` | 检索记忆(quick/deep/hybrid/keyword + drill 钻取) |
|
|
234
|
+
| `memory_list` | 列出记忆(分页 + 状态/类型/强度/关键词过滤 + 排序) |
|
|
211
235
|
| `memory_manage` | 管理生命周期(forget/reinforce/consolidate/reclaim/reembed) |
|
|
212
236
|
| `memory_evolve` | 自动进化(extract 提取 + persona 画像更新) |
|
|
213
237
|
| `memory_compress` | 压缩记忆(compress/decompress/offload) |
|
package/dist/index.js
CHANGED
|
@@ -943,6 +943,40 @@ var Storage = class _Storage {
|
|
|
943
943
|
`);
|
|
944
944
|
return rows.map((r) => this.rowToMemory(r));
|
|
945
945
|
}
|
|
946
|
+
/**
|
|
947
|
+
* 分页列出记忆,支持按 status / type / permanent / 强度区间 / 关键词过滤,
|
|
948
|
+
* 支持白名单字段排序。返回 { items, total } —— total 是过滤后总条数
|
|
949
|
+
* (不受分页影响),用于客户端计算 has_more / 总页数。
|
|
950
|
+
*
|
|
951
|
+
* 与 getActiveMemories/getMemoriesByStatus 的区别:本方法做确定性分页浏览,
|
|
952
|
+
* 不依赖语义检索,专供 memory_list 工具浏览全库使用。
|
|
953
|
+
*/
|
|
954
|
+
async listMemories(opts) {
|
|
955
|
+
const conditions = [];
|
|
956
|
+
if (opts.status) conditions.push(`status = '${this.escape(opts.status)}'`);
|
|
957
|
+
if (opts.type) conditions.push(`type = '${this.escape(opts.type)}'`);
|
|
958
|
+
if (opts.permanent !== void 0) conditions.push(`permanent = ${opts.permanent ? "true" : "false"}`);
|
|
959
|
+
if (opts.minStrength !== void 0) conditions.push(`strength >= ${Number(opts.minStrength)}`);
|
|
960
|
+
if (opts.maxStrength !== void 0) conditions.push(`strength <= ${Number(opts.maxStrength)}`);
|
|
961
|
+
if (opts.q) conditions.push(`content LIKE '%${this.escape(opts.q)}%'`);
|
|
962
|
+
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
963
|
+
const validOrderBy = /* @__PURE__ */ new Set([
|
|
964
|
+
"created_at",
|
|
965
|
+
"strength",
|
|
966
|
+
"importance",
|
|
967
|
+
"last_accessed",
|
|
968
|
+
"access_count"
|
|
969
|
+
]);
|
|
970
|
+
const orderBy = validOrderBy.has(opts.orderBy ?? "") ? opts.orderBy : "created_at";
|
|
971
|
+
const order = opts.order === "asc" ? "ASC" : "DESC";
|
|
972
|
+
const limit = Math.min(Math.max(opts.limit ?? 20, 1), 500);
|
|
973
|
+
const offset = Math.max(opts.offset ?? 0, 0);
|
|
974
|
+
const total = this.N((await this.get(`SELECT COUNT(*) as c FROM memories ${where}`))?.c) ?? 0;
|
|
975
|
+
const rows = await this.all(
|
|
976
|
+
`SELECT * FROM memories ${where} ORDER BY ${orderBy} ${order} LIMIT ${limit} OFFSET ${offset}`
|
|
977
|
+
);
|
|
978
|
+
return { items: rows.map((r) => this.rowToMemory(r)), total };
|
|
979
|
+
}
|
|
946
980
|
async updateMemoryBatch(ids, updates) {
|
|
947
981
|
for (const id of ids) {
|
|
948
982
|
await this.updateMemory(id, updates);
|
|
@@ -21662,6 +21696,111 @@ async function handleMetrics(deps) {
|
|
|
21662
21696
|
return { content: [{ type: "text", text: JSON.stringify({ metrics, report }, null, 2) }] };
|
|
21663
21697
|
}
|
|
21664
21698
|
|
|
21699
|
+
// src/tools/memory-list.ts
|
|
21700
|
+
var TRUNC_LIGHT = 100;
|
|
21701
|
+
function serializeLight(m, fullContent) {
|
|
21702
|
+
const item = {
|
|
21703
|
+
memory_id: m.id,
|
|
21704
|
+
type: m.type,
|
|
21705
|
+
status: m.status,
|
|
21706
|
+
strength: Number(m.strength?.toFixed(3)),
|
|
21707
|
+
permanent: m.permanent
|
|
21708
|
+
};
|
|
21709
|
+
if (fullContent || m.content.length <= TRUNC_LIGHT) {
|
|
21710
|
+
item.content = m.content;
|
|
21711
|
+
item.content_length = m.content.length;
|
|
21712
|
+
} else {
|
|
21713
|
+
item.content = m.content.slice(0, TRUNC_LIGHT) + "...";
|
|
21714
|
+
item.content_length = m.content.length;
|
|
21715
|
+
item.content_truncated = true;
|
|
21716
|
+
}
|
|
21717
|
+
item.created_at_iso = m.created_at ? new Date(m.created_at).toISOString() : null;
|
|
21718
|
+
return item;
|
|
21719
|
+
}
|
|
21720
|
+
function serializeDetail(m, fullContent) {
|
|
21721
|
+
const TRUNC_DETAIL = 300;
|
|
21722
|
+
const item = {
|
|
21723
|
+
memory_id: m.id,
|
|
21724
|
+
type: m.type,
|
|
21725
|
+
status: m.status,
|
|
21726
|
+
strength: Number(m.strength?.toFixed(3)),
|
|
21727
|
+
importance: Number(m.importance?.toFixed(3)),
|
|
21728
|
+
permanent: m.permanent,
|
|
21729
|
+
tags: m.tags,
|
|
21730
|
+
access_count: m.access_count,
|
|
21731
|
+
created_at: m.created_at,
|
|
21732
|
+
created_at_iso: m.created_at ? new Date(m.created_at).toISOString() : null,
|
|
21733
|
+
last_accessed: m.last_accessed,
|
|
21734
|
+
last_accessed_iso: m.last_accessed ? new Date(m.last_accessed).toISOString() : null,
|
|
21735
|
+
anchor_id: m.anchor_id,
|
|
21736
|
+
compressed: m.compressed
|
|
21737
|
+
};
|
|
21738
|
+
if (fullContent || m.content.length <= TRUNC_DETAIL) {
|
|
21739
|
+
item.content = m.content;
|
|
21740
|
+
item.content_length = m.content.length;
|
|
21741
|
+
} else {
|
|
21742
|
+
item.content = m.content.slice(0, TRUNC_DETAIL) + "...";
|
|
21743
|
+
item.content_length = m.content.length;
|
|
21744
|
+
item.content_truncated = true;
|
|
21745
|
+
}
|
|
21746
|
+
return item;
|
|
21747
|
+
}
|
|
21748
|
+
function registerMemoryList(server, deps) {
|
|
21749
|
+
server.tool(
|
|
21750
|
+
"memory_list",
|
|
21751
|
+
"\u5217\u51FA\u8BB0\u5FC6\uFF1A\u5206\u9875\u67E5\u8BE2\u3001\u6309\u7C7B\u578B/\u72B6\u6001/\u5F3A\u5EA6/\u5173\u952E\u8BCD\u8FC7\u6EE4\u3001\u652F\u6301\u6392\u5E8F",
|
|
21752
|
+
{
|
|
21753
|
+
status: external_exports.enum(["active", "infrequent", "archived"]).optional().describe("\u72B6\u6001\u8FC7\u6EE4\uFF1B\u4E0D\u4F20=\u5168\u90E8"),
|
|
21754
|
+
type: external_exports.enum(["fact", "preference", "instruction", "event", "skill"]).optional().describe("\u7C7B\u578B\u8FC7\u6EE4"),
|
|
21755
|
+
permanent: external_exports.boolean().optional().describe("\u53EA\u770B\u6C38\u4E45\u8BB0\u5FC6\uFF08true\uFF09/\u53EA\u770B\u975E\u6C38\u4E45\uFF08false\uFF09\uFF1B\u4E0D\u4F20=\u5168\u90E8"),
|
|
21756
|
+
min_strength: external_exports.number().optional().describe("\u6700\u4F4E\u5F3A\u5EA6\u8FC7\u6EE4\uFF080-1\uFF09"),
|
|
21757
|
+
max_strength: external_exports.number().optional().describe("\u6700\u9AD8\u5F3A\u5EA6\u8FC7\u6EE4\uFF080-1\uFF09"),
|
|
21758
|
+
q: external_exports.string().optional().describe("\u5173\u952E\u8BCD\u6A21\u7CCA\u5339\u914D\uFF08LIKE\uFF09\uFF0C\u53EF\u9009"),
|
|
21759
|
+
order_by: external_exports.enum(["created_at", "strength", "importance", "last_accessed", "access_count"]).optional().describe("\u6392\u5E8F\u5B57\u6BB5\uFF0C\u9ED8\u8BA4 created_at"),
|
|
21760
|
+
order: external_exports.enum(["asc", "desc"]).optional().describe("\u6392\u5E8F\u65B9\u5411\uFF0C\u9ED8\u8BA4 desc"),
|
|
21761
|
+
limit: external_exports.number().optional().describe("\u6BCF\u9875\u6570\u91CF\uFF0C\u9ED8\u8BA4 20\uFF0C\u786C\u4E0A\u9650 500"),
|
|
21762
|
+
offset: external_exports.number().optional().describe("\u504F\u79FB\u91CF\uFF0C\u9ED8\u8BA4 0"),
|
|
21763
|
+
detail: external_exports.boolean().optional().describe("\u8FD4\u56DE\u5168\u5B57\u6BB5\uFF08importance/tags/access_count \u7B49\uFF09\uFF1B\u9ED8\u8BA4 false \u53EA\u8FD4\u56DE\u6838\u5FC3\u5B57\u6BB5"),
|
|
21764
|
+
full_content: external_exports.boolean().optional().describe("\u8FD4\u56DE\u5B8C\u6574 content\uFF08\u9ED8\u8BA4 light \u622A\u65AD\u5230 100 \u5B57\u7B26\uFF0Cdetail \u622A\u65AD\u5230 300\uFF09")
|
|
21765
|
+
},
|
|
21766
|
+
async (params) => {
|
|
21767
|
+
const { storage } = deps;
|
|
21768
|
+
const limit = Math.min(Math.max(params.limit ?? 20, 1), 500);
|
|
21769
|
+
const offset = Math.max(params.offset ?? 0, 0);
|
|
21770
|
+
const fullContent = params.full_content ?? false;
|
|
21771
|
+
const detail = params.detail ?? false;
|
|
21772
|
+
const { items, total } = await storage.listMemories({
|
|
21773
|
+
status: params.status,
|
|
21774
|
+
type: params.type,
|
|
21775
|
+
permanent: params.permanent,
|
|
21776
|
+
minStrength: params.min_strength,
|
|
21777
|
+
maxStrength: params.max_strength,
|
|
21778
|
+
q: params.q,
|
|
21779
|
+
orderBy: params.order_by,
|
|
21780
|
+
order: params.order,
|
|
21781
|
+
limit,
|
|
21782
|
+
offset
|
|
21783
|
+
});
|
|
21784
|
+
const serialized = items.map(
|
|
21785
|
+
(m) => detail ? serializeDetail(m, fullContent) : serializeLight(m, fullContent)
|
|
21786
|
+
);
|
|
21787
|
+
return {
|
|
21788
|
+
content: [{
|
|
21789
|
+
type: "text",
|
|
21790
|
+
text: JSON.stringify({
|
|
21791
|
+
items: serialized,
|
|
21792
|
+
total,
|
|
21793
|
+
limit,
|
|
21794
|
+
offset,
|
|
21795
|
+
mode: detail ? "detail" : "light",
|
|
21796
|
+
has_more: offset + items.length < total
|
|
21797
|
+
}, null, 2)
|
|
21798
|
+
}]
|
|
21799
|
+
};
|
|
21800
|
+
}
|
|
21801
|
+
);
|
|
21802
|
+
}
|
|
21803
|
+
|
|
21665
21804
|
// src/index.ts
|
|
21666
21805
|
BigInt.prototype.toJSON = function() {
|
|
21667
21806
|
return Number(this);
|
|
@@ -21748,7 +21887,7 @@ async function main() {
|
|
|
21748
21887
|
const createMcpServer = () => {
|
|
21749
21888
|
const server = new McpServer({
|
|
21750
21889
|
name: "MMPL",
|
|
21751
|
-
version: "2.
|
|
21890
|
+
version: "2.8.0"
|
|
21752
21891
|
});
|
|
21753
21892
|
registerMemoryWrite(server, deps);
|
|
21754
21893
|
registerMemorySearch(server, deps);
|
|
@@ -21758,6 +21897,7 @@ async function main() {
|
|
|
21758
21897
|
registerMemoryPalace(server, deps);
|
|
21759
21898
|
registerMemorySymbol(server, deps);
|
|
21760
21899
|
registerMemoryStats(server, deps);
|
|
21900
|
+
registerMemoryList(server, deps);
|
|
21761
21901
|
return server;
|
|
21762
21902
|
};
|
|
21763
21903
|
const httpHost = process.env.MCP_HTTP_HOST ?? "127.0.0.1";
|
|
@@ -21771,7 +21911,7 @@ async function main() {
|
|
|
21771
21911
|
void embeddingService.ready().catch((err) => {
|
|
21772
21912
|
console.error("[startup] embedding service init failed:", err);
|
|
21773
21913
|
});
|
|
21774
|
-
console.error(`MMPL (Memory Palace) MCP Server v2.
|
|
21914
|
+
console.error(`MMPL (Memory Palace) MCP Server v2.8.0 listening on http://${httpHost}:${httpPort}${httpPath}`);
|
|
21775
21915
|
const gracefulShutdown = async (signal) => {
|
|
21776
21916
|
console.error(`
|
|
21777
21917
|
[shutdown] Received ${signal}, gracefully shutting down...`);
|