exomind 0.2.6 → 0.3.1
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 +20 -6
- package/dist/cli.js +182 -6
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,19 +42,33 @@ exomind feedback "entities/Redis.md" positive
|
|
|
42
42
|
|
|
43
43
|
加 `--json` 获取机器可读输出(脚本/管道):`exomind --json stats | jq .total_nodes`。
|
|
44
44
|
|
|
45
|
-
## 接入 Claude Code
|
|
45
|
+
## 接入 Claude Code(一条命令,默认全装)
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
exomind install
|
|
48
|
+
exomind install # 装 skill + hook + MCP,全部自动(幂等+备份)
|
|
49
|
+
# 不想要某项: exomind install --no-hook 或 --no-mcp
|
|
49
50
|
```
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
一行完成三层,免手改任何 JSON:
|
|
53
|
+
- **① MCP 工具**(能力):写 `~/.claude.json` 的 `mcpServers.exomind` → Agent 拿到 `mcp__exomind__*` 确定性工具。
|
|
54
|
+
- **② skill**(指导):拷到 `~/.claude/skills/exomind/`。
|
|
55
|
+
- **③ hook**(闸门):写 `settings.json` 的 `UserPromptSubmit → exomind hook`。
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
重启 Claude Code 后:
|
|
58
|
+
- 说 **`存档`** / **`jdit`** → 自动回顾会话、摄入。
|
|
54
59
|
- 提问涉及知识库已有实体 → 自动注入 `[ExoMind 知识库上下文]`。
|
|
55
|
-
-
|
|
60
|
+
- Agent 需查询/摄入时 → 直接调 `mcp__exomind__*`(确定),或按 skill 跑 `exomind` CLI。
|
|
56
61
|
|
|
57
|
-
|
|
62
|
+
完整接入步骤见服务端仓库 `myExoMindManager/docs/new-machine-setup.md`。
|
|
63
|
+
|
|
64
|
+
## 关于 MCP 工具层(Claude Code 已默认装;OpenCode 需手写)
|
|
65
|
+
|
|
66
|
+
`exomind install` 已默认把 MCP 写进 Claude Code 的 `~/.claude.json`(见上)。这里仅给**其它宿主/手写**场景:
|
|
67
|
+
|
|
68
|
+
- **OpenCode**(`opencode.json`):`{ "mcp": { "exomind": { "type": "local", "command": ["exomind", "mcp"] } } }`
|
|
69
|
+
- **手写 Claude Code**:`~/.claude.json` 或项目 `.mcp.json`:`{ "mcpServers": { "exomind": { "command": "exomind", "args": ["mcp"] } } }`
|
|
70
|
+
|
|
71
|
+
`exomind mcp` 是本地 stdio MCP server,把 ingest/query/search/entity/relations/stats 暴露为 typed tool;复用同一份凭证,三平台都能跑(本地 stdio,不涉及远程 SSE 的 Windows 坑)。详见 [三层模式说明](./docs/mcp.md)。
|
|
58
72
|
|
|
59
73
|
## 命令一览
|
|
60
74
|
|
package/dist/cli.js
CHANGED
|
@@ -3119,7 +3119,7 @@ var {
|
|
|
3119
3119
|
// package.json
|
|
3120
3120
|
var package_default = {
|
|
3121
3121
|
name: "exomind",
|
|
3122
|
-
version: "0.
|
|
3122
|
+
version: "0.3.1",
|
|
3123
3123
|
description: "ExoMind \u8DE8\u5E73\u53F0\u547D\u4EE4\u884C\u5BA2\u6237\u7AEF \u2014 \u901A\u8FC7 REST \u4E0E ExoMind \u77E5\u8BC6\u5E93\u4EA4\u4E92(ingest/query/search/review),\u66FF\u4EE3 Windows \u4E0D\u53EF\u7528\u7684 MCP \u5BA2\u6237\u7AEF\u3002",
|
|
3124
3124
|
bin: {
|
|
3125
3125
|
exomind: "dist/cli.js"
|
|
@@ -3624,6 +3624,160 @@ async function runHook(client) {
|
|
|
3624
3624
|
}
|
|
3625
3625
|
}
|
|
3626
3626
|
|
|
3627
|
+
// src/mcp.ts
|
|
3628
|
+
var readline = __toESM(require("readline"));
|
|
3629
|
+
var PROTOCOL_VERSION = "2024-11-05";
|
|
3630
|
+
var TOOLS = [
|
|
3631
|
+
{
|
|
3632
|
+
name: "ingest",
|
|
3633
|
+
description: "\u5411 ExoMind \u77E5\u8BC6\u5E93\u5BFC\u5165\u77E5\u8BC6(\u6587\u672C),\u81EA\u52A8\u62BD\u53D6\u5B9E\u4F53/\u5173\u7CFB\u3002",
|
|
3634
|
+
inputSchema: {
|
|
3635
|
+
type: "object",
|
|
3636
|
+
properties: {
|
|
3637
|
+
content: { type: "string", description: "\u8981\u5BFC\u5165\u7684\u6587\u672C\u5185\u5BB9" },
|
|
3638
|
+
title: { type: "string", description: "\u6807\u9898(\u53EF\u9009)" },
|
|
3639
|
+
tags: { type: "array", items: { type: "string" }, description: "\u6807\u7B7E(\u53EF\u9009)" }
|
|
3640
|
+
},
|
|
3641
|
+
required: ["content"]
|
|
3642
|
+
}
|
|
3643
|
+
},
|
|
3644
|
+
{
|
|
3645
|
+
name: "query",
|
|
3646
|
+
description: "LLM \u95EE\u7B54:\u57FA\u4E8E\u77E5\u8BC6\u5E93\u56DE\u7B54\u95EE\u9898\u3002",
|
|
3647
|
+
inputSchema: {
|
|
3648
|
+
type: "object",
|
|
3649
|
+
properties: {
|
|
3650
|
+
question: { type: "string", description: "\u95EE\u9898" },
|
|
3651
|
+
tags: { type: "array", items: { type: "string" }, description: "\u6807\u7B7E\u8FC7\u6EE4(\u53EF\u9009)" }
|
|
3652
|
+
},
|
|
3653
|
+
required: ["question"]
|
|
3654
|
+
}
|
|
3655
|
+
},
|
|
3656
|
+
{
|
|
3657
|
+
name: "search",
|
|
3658
|
+
description: "\u5168\u6587\u641C\u7D22\u77E5\u8BC6\u5E93\u3002",
|
|
3659
|
+
inputSchema: {
|
|
3660
|
+
type: "object",
|
|
3661
|
+
properties: {
|
|
3662
|
+
keyword: { type: "string", description: "\u5173\u952E\u8BCD" },
|
|
3663
|
+
limit: { type: "integer", description: "\u8FD4\u56DE\u6570\u91CF(\u9ED8\u8BA4 10)" }
|
|
3664
|
+
},
|
|
3665
|
+
required: ["keyword"]
|
|
3666
|
+
}
|
|
3667
|
+
},
|
|
3668
|
+
{
|
|
3669
|
+
name: "entity",
|
|
3670
|
+
description: "\u83B7\u53D6\u5B9E\u4F53\u8BE6\u60C5(\u63CF\u8FF0\u3001\u522B\u540D\u3001\u5173\u7CFB)\u3002",
|
|
3671
|
+
inputSchema: {
|
|
3672
|
+
type: "object",
|
|
3673
|
+
properties: { name: { type: "string", description: "\u5B9E\u4F53\u540D\u79F0" } },
|
|
3674
|
+
required: ["name"]
|
|
3675
|
+
}
|
|
3676
|
+
},
|
|
3677
|
+
{
|
|
3678
|
+
name: "relations",
|
|
3679
|
+
description: "\u83B7\u53D6\u5B9E\u4F53\u7684\u5173\u8054\u5B9E\u4F53(\u53EF\u8FBE\u6027)\u3002",
|
|
3680
|
+
inputSchema: {
|
|
3681
|
+
type: "object",
|
|
3682
|
+
properties: {
|
|
3683
|
+
name: { type: "string", description: "\u5B9E\u4F53\u540D\u79F0" },
|
|
3684
|
+
depth: { type: "integer", description: "\u6DF1\u5EA6 1-3(\u9ED8\u8BA4 1)" }
|
|
3685
|
+
},
|
|
3686
|
+
required: ["name"]
|
|
3687
|
+
}
|
|
3688
|
+
},
|
|
3689
|
+
{
|
|
3690
|
+
name: "stats",
|
|
3691
|
+
description: "\u77E5\u8BC6\u5E93\u7EDF\u8BA1(\u8282\u70B9/\u5173\u7CFB\u6570)\u3002",
|
|
3692
|
+
inputSchema: { type: "object", properties: {} }
|
|
3693
|
+
}
|
|
3694
|
+
];
|
|
3695
|
+
async function handleTool(client, name, args) {
|
|
3696
|
+
switch (name) {
|
|
3697
|
+
case "ingest":
|
|
3698
|
+
return client.post("/ingest", args, { timeoutMs: opTimeout(3e5) });
|
|
3699
|
+
case "query":
|
|
3700
|
+
return client.post("/query", args, { timeoutMs: opTimeout(18e4) });
|
|
3701
|
+
case "search":
|
|
3702
|
+
return client.get("/search", { q: args.keyword ?? args.q, limit: args.limit ?? 10 });
|
|
3703
|
+
case "entity":
|
|
3704
|
+
return client.get(`/entities/${encodeURIComponent(String(args.name))}`);
|
|
3705
|
+
case "relations":
|
|
3706
|
+
return client.get(`/relations/${encodeURIComponent(String(args.name))}`, { depth: args.depth ?? 1 });
|
|
3707
|
+
case "stats":
|
|
3708
|
+
return client.get("/stats");
|
|
3709
|
+
default:
|
|
3710
|
+
throw new Error(`\u672A\u77E5\u5DE5\u5177: ${name}`);
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
async function handleMessage(client, msg) {
|
|
3714
|
+
const id = msg.id;
|
|
3715
|
+
const method = msg.method;
|
|
3716
|
+
if (method === "initialize") {
|
|
3717
|
+
return {
|
|
3718
|
+
jsonrpc: "2.0",
|
|
3719
|
+
id,
|
|
3720
|
+
result: {
|
|
3721
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
3722
|
+
capabilities: { tools: {} },
|
|
3723
|
+
serverInfo: { name: "exomind", version: package_default.version }
|
|
3724
|
+
}
|
|
3725
|
+
};
|
|
3726
|
+
}
|
|
3727
|
+
if (method === "notifications/initialized" || method === "initialized") return null;
|
|
3728
|
+
if (method === "ping") return { jsonrpc: "2.0", id, result: {} };
|
|
3729
|
+
if (method === "tools/list") return { jsonrpc: "2.0", id, result: { tools: TOOLS } };
|
|
3730
|
+
if (method === "tools/call") {
|
|
3731
|
+
const params = msg.params ?? {};
|
|
3732
|
+
try {
|
|
3733
|
+
const data = await handleTool(client, params.name ?? "", params.arguments ?? {});
|
|
3734
|
+
return {
|
|
3735
|
+
jsonrpc: "2.0",
|
|
3736
|
+
id,
|
|
3737
|
+
result: {
|
|
3738
|
+
content: [{ type: "text", text: typeof data === "string" ? data : JSON.stringify(data, null, 2) }]
|
|
3739
|
+
}
|
|
3740
|
+
};
|
|
3741
|
+
} catch (e) {
|
|
3742
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
3743
|
+
return {
|
|
3744
|
+
jsonrpc: "2.0",
|
|
3745
|
+
id,
|
|
3746
|
+
result: { content: [{ type: "text", text: `\u9519\u8BEF: ${message}` }], isError: true }
|
|
3747
|
+
};
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
return { jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown method: ${method}` } };
|
|
3751
|
+
}
|
|
3752
|
+
async function runMcpServer(client) {
|
|
3753
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
3754
|
+
rl.on("line", async (line) => {
|
|
3755
|
+
const trimmed = line.trim();
|
|
3756
|
+
if (!trimmed) return;
|
|
3757
|
+
let msg;
|
|
3758
|
+
try {
|
|
3759
|
+
msg = JSON.parse(trimmed);
|
|
3760
|
+
} catch {
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
try {
|
|
3764
|
+
const resp = await handleMessage(client, msg);
|
|
3765
|
+
if (resp) process.stdout.write(JSON.stringify(resp) + "\n");
|
|
3766
|
+
} catch (e) {
|
|
3767
|
+
process.stdout.write(
|
|
3768
|
+
JSON.stringify({
|
|
3769
|
+
jsonrpc: "2.0",
|
|
3770
|
+
id: msg?.id ?? null,
|
|
3771
|
+
error: { code: -32603, message: e instanceof Error ? e.message : String(e) }
|
|
3772
|
+
}) + "\n"
|
|
3773
|
+
);
|
|
3774
|
+
}
|
|
3775
|
+
});
|
|
3776
|
+
return new Promise((resolve6) => {
|
|
3777
|
+
rl.on("close", () => resolve6());
|
|
3778
|
+
});
|
|
3779
|
+
}
|
|
3780
|
+
|
|
3627
3781
|
// src/commands/ingest.ts
|
|
3628
3782
|
var path5 = __toESM(require("path"));
|
|
3629
3783
|
|
|
@@ -4056,10 +4210,10 @@ async function daily(client, opts) {
|
|
|
4056
4210
|
}
|
|
4057
4211
|
|
|
4058
4212
|
// src/commands/login.ts
|
|
4059
|
-
var
|
|
4213
|
+
var readline2 = __toESM(require("readline/promises"));
|
|
4060
4214
|
var import_node_process = require("process");
|
|
4061
4215
|
async function prompt(question) {
|
|
4062
|
-
const rl =
|
|
4216
|
+
const rl = readline2.createInterface({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
4063
4217
|
try {
|
|
4064
4218
|
return (await rl.question(question)).trim();
|
|
4065
4219
|
} finally {
|
|
@@ -4154,7 +4308,7 @@ async function install(_client, opts) {
|
|
|
4154
4308
|
fs6.copyFileSync(SKILL_SRC, path6.join(skillDestDir, "SKILL.md"));
|
|
4155
4309
|
console.log(ok("\u5DF2\u5B89\u88C5 Claude Code skill"));
|
|
4156
4310
|
console.log(dim(` \u2192 ${skillDestDir}/SKILL.md`));
|
|
4157
|
-
if (opts.
|
|
4311
|
+
if (opts.hook !== false) {
|
|
4158
4312
|
const settingsFile = path6.join(claudeDir, "settings.json");
|
|
4159
4313
|
fs6.mkdirSync(claudeDir, { recursive: true });
|
|
4160
4314
|
backup(settingsFile);
|
|
@@ -4173,9 +4327,20 @@ async function install(_client, opts) {
|
|
|
4173
4327
|
console.log(ok("\u5DF2\u914D\u7F6E UserPromptSubmit hook \u2192 exomind hook"));
|
|
4174
4328
|
console.log(dim(" \u91CD\u542F Claude Code \u751F\u6548\u3002hook \u51FA\u9519\u4E0D\u4F1A\u963B\u585E\u4F60\u7684\u8F93\u5165(\u9519\u8BEF\u53EA\u8FDB stderr)\u3002"));
|
|
4175
4329
|
}
|
|
4330
|
+
if (opts.mcp !== false) {
|
|
4331
|
+
const claudeJson = path6.join(os2.homedir(), ".claude.json");
|
|
4332
|
+
backup(claudeJson);
|
|
4333
|
+
const cc = readJson2(claudeJson) ?? {};
|
|
4334
|
+
const mcpServers = cc.mcpServers ?? {};
|
|
4335
|
+
mcpServers.exomind = { command: "exomind", args: ["mcp"] };
|
|
4336
|
+
cc.mcpServers = mcpServers;
|
|
4337
|
+
fs6.writeFileSync(claudeJson, JSON.stringify(cc, null, 2) + "\n");
|
|
4338
|
+
console.log(ok("\u5DF2\u914D\u7F6E MCP server \u2192 exomind mcp"));
|
|
4339
|
+
console.log(dim(" \u2192 ~/.claude.json (mcpServers.exomind);\u91CD\u542F Claude Code \u540E Agent \u62FF\u5230 mcp__exomind__* \u5DE5\u5177"));
|
|
4340
|
+
}
|
|
4176
4341
|
console.log(yellow("\n\u4E0B\u4E00\u6B65:"));
|
|
4177
4342
|
console.log(dim(" 1. \u82E5\u672A\u914D\u7F6E\u51ED\u8BC1: exomind login"));
|
|
4178
|
-
console.log(dim(" 2. \u91CD\u542F Claude Code
|
|
4343
|
+
console.log(dim(" 2. \u91CD\u542F Claude Code \u2192 skill + hook + mcp__exomind__* \u5168\u90E8\u751F\u6548"));
|
|
4179
4344
|
}
|
|
4180
4345
|
|
|
4181
4346
|
// src/cli.ts
|
|
@@ -4248,7 +4413,18 @@ program2.command("hook").description("UserPromptSubmit \u94A9\u5B50(\u7531 Claud
|
|
|
4248
4413
|
}
|
|
4249
4414
|
process.exit(0);
|
|
4250
4415
|
});
|
|
4251
|
-
program2.command("
|
|
4416
|
+
program2.command("mcp").description("\u542F\u52A8 stdio MCP server(\u4F9B Claude Code/OpenCode/Cursor \u4F5C\u4E3A MCP \u5DE5\u5177\u63A5\u5165)").action(async (...a) => {
|
|
4417
|
+
const command = a[a.length - 1];
|
|
4418
|
+
const root = rootOptions(command);
|
|
4419
|
+
setJsonMode(false);
|
|
4420
|
+
const cfg = resolveConfig({
|
|
4421
|
+
baseUrl: root.baseUrl,
|
|
4422
|
+
apiKey: root.apiKey
|
|
4423
|
+
});
|
|
4424
|
+
const client = new ApiClient(cfg);
|
|
4425
|
+
await runMcpServer(client);
|
|
4426
|
+
});
|
|
4427
|
+
program2.command("install").description("\u5B89\u88C5 skill + hook + MCP(\u9ED8\u8BA4\u5168\u88C5;--no-hook / --no-mcp \u5173\u95ED\u67D0\u9879)").option("--no-hook", "\u4E0D\u5199 UserPromptSubmit hook").option("--no-mcp", "\u4E0D\u5199 MCP server \u914D\u7F6E").action(run(install));
|
|
4252
4428
|
async function main() {
|
|
4253
4429
|
const first = process.argv[2];
|
|
4254
4430
|
if (first && /^(-v|--version)$/.test(first)) {
|