exomind 0.3.8 → 0.3.10
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/dist/cli.js +92 -15
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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.3.
|
|
3122
|
+
version: "0.3.10",
|
|
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"
|
|
@@ -3890,6 +3890,24 @@ function planIngestest(files, manifest, force) {
|
|
|
3890
3890
|
}
|
|
3891
3891
|
return { toIngest, toSkip };
|
|
3892
3892
|
}
|
|
3893
|
+
async function mapWithConcurrency(items, concurrency, worker) {
|
|
3894
|
+
const size = items.length;
|
|
3895
|
+
const n = Math.max(1, Math.min(concurrency, size));
|
|
3896
|
+
let next = 0;
|
|
3897
|
+
const runners = [];
|
|
3898
|
+
for (let w = 0; w < n; w++) {
|
|
3899
|
+
runners.push(
|
|
3900
|
+
(async () => {
|
|
3901
|
+
while (true) {
|
|
3902
|
+
const idx = next++;
|
|
3903
|
+
if (idx >= size) break;
|
|
3904
|
+
await worker(items[idx], idx);
|
|
3905
|
+
}
|
|
3906
|
+
})()
|
|
3907
|
+
);
|
|
3908
|
+
}
|
|
3909
|
+
await Promise.all(runners);
|
|
3910
|
+
}
|
|
3893
3911
|
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
3894
3912
|
var suspended = false;
|
|
3895
3913
|
async function ingestWithRetry(client, payload, timeoutMs) {
|
|
@@ -3948,8 +3966,9 @@ async function runDirIngestest(client, opts, dir) {
|
|
|
3948
3966
|
const manifest = loadManifest();
|
|
3949
3967
|
const plan = planIngestest(files, manifest, !!opts.force);
|
|
3950
3968
|
const total = files.length;
|
|
3969
|
+
const concurrency = Math.max(1, opts.concurrency ?? 3);
|
|
3951
3970
|
process.stderr.write(
|
|
3952
|
-
`\u76EE\u5F55 ${dir}: ${total} \u6587\u4EF6 \u2014 \u5F85\u6444\u5165 ${plan.toIngest.length},\u8DF3\u8FC7 ${plan.toSkip.length}
|
|
3971
|
+
`\u76EE\u5F55 ${dir}: ${total} \u6587\u4EF6 \u2014 \u5F85\u6444\u5165 ${plan.toIngest.length},\u8DF3\u8FC7 ${plan.toSkip.length}(\u5E76\u53D1 ${concurrency})
|
|
3953
3972
|
`
|
|
3954
3973
|
);
|
|
3955
3974
|
const onSigInt = () => {
|
|
@@ -3963,11 +3982,13 @@ async function runDirIngestest(client, opts, dir) {
|
|
|
3963
3982
|
let added = 0;
|
|
3964
3983
|
let updated = 0;
|
|
3965
3984
|
let failed = 0;
|
|
3985
|
+
let started = 0;
|
|
3986
|
+
const queue = plan.toIngest;
|
|
3966
3987
|
try {
|
|
3967
|
-
|
|
3968
|
-
const f = plan.toIngest[i];
|
|
3988
|
+
await mapWithConcurrency(queue, concurrency, async (f) => {
|
|
3969
3989
|
const prev = manifest[f.path];
|
|
3970
|
-
|
|
3990
|
+
const seq = ++started;
|
|
3991
|
+
process.stderr.write(`\u23F3 [${seq}/${queue.length}] ${path4.basename(f.path)}\u2026
|
|
3971
3992
|
`);
|
|
3972
3993
|
try {
|
|
3973
3994
|
const res = await ingestWithRetry(
|
|
@@ -3991,7 +4012,7 @@ async function runDirIngestest(client, opts, dir) {
|
|
|
3991
4012
|
process.stderr.write(` ${red("\u2717")} ${e.message}
|
|
3992
4013
|
`);
|
|
3993
4014
|
}
|
|
3994
|
-
}
|
|
4015
|
+
});
|
|
3995
4016
|
cleanupStale(manifest, dir, files);
|
|
3996
4017
|
saveManifest(manifest);
|
|
3997
4018
|
} finally {
|
|
@@ -4360,6 +4381,7 @@ async function whoami(client) {
|
|
|
4360
4381
|
var fs6 = __toESM(require("fs"));
|
|
4361
4382
|
var path6 = __toESM(require("path"));
|
|
4362
4383
|
var os2 = __toESM(require("os"));
|
|
4384
|
+
var import_node_child_process = require("child_process");
|
|
4363
4385
|
var PKG_ROOT = path6.resolve(__dirname, "..");
|
|
4364
4386
|
var SKILL_SRC = path6.join(PKG_ROOT, "skill", "SKILL.md");
|
|
4365
4387
|
function readJson2(file) {
|
|
@@ -4405,6 +4427,50 @@ function purgeMcpExomind(file) {
|
|
|
4405
4427
|
fs6.writeFileSync(file, JSON.stringify(d, null, 2) + "\n");
|
|
4406
4428
|
return true;
|
|
4407
4429
|
}
|
|
4430
|
+
function checkMcp(timeoutMs = 6e3) {
|
|
4431
|
+
return new Promise((resolve6) => {
|
|
4432
|
+
let child;
|
|
4433
|
+
try {
|
|
4434
|
+
child = (0, import_node_child_process.spawn)("exomind", ["mcp"], { stdio: ["pipe", "pipe", "pipe"], shell: true });
|
|
4435
|
+
} catch (e) {
|
|
4436
|
+
resolve6({ ok: false, detail: `\u65E0\u6CD5\u542F\u52A8: ${e instanceof Error ? e.message : e}` });
|
|
4437
|
+
return;
|
|
4438
|
+
}
|
|
4439
|
+
let out = "";
|
|
4440
|
+
let done = false;
|
|
4441
|
+
const finish = (r) => {
|
|
4442
|
+
if (done) return;
|
|
4443
|
+
done = true;
|
|
4444
|
+
clearTimeout(timer);
|
|
4445
|
+
try {
|
|
4446
|
+
child.kill();
|
|
4447
|
+
} catch {
|
|
4448
|
+
}
|
|
4449
|
+
resolve6(r);
|
|
4450
|
+
};
|
|
4451
|
+
const timer = setTimeout(() => finish({ ok: false, detail: "\u8D85\u65F6\u672A\u54CD\u5E94 initialize" }), timeoutMs);
|
|
4452
|
+
child.stdout?.on("data", (d) => {
|
|
4453
|
+
out += d.toString();
|
|
4454
|
+
if (out.includes('"serverInfo"')) finish({ ok: true, detail: "initialize \u54CD\u5E94\u6B63\u5E38" });
|
|
4455
|
+
});
|
|
4456
|
+
child.on("error", (e) => finish({ ok: false, detail: `\u542F\u52A8\u5931\u8D25: ${e.message}` }));
|
|
4457
|
+
child.on("close", () => {
|
|
4458
|
+
if (!out.includes('"serverInfo"')) finish({ ok: false, detail: "\u672A\u54CD\u5E94 initialize \u5373\u9000\u51FA" });
|
|
4459
|
+
});
|
|
4460
|
+
try {
|
|
4461
|
+
child.stdin?.write(
|
|
4462
|
+
JSON.stringify({
|
|
4463
|
+
jsonrpc: "2.0",
|
|
4464
|
+
method: "initialize",
|
|
4465
|
+
params: { protocolVersion: "2024-11-05", capabilities: {}, clientInfo: { name: "install-check", version: "1" } },
|
|
4466
|
+
id: 1
|
|
4467
|
+
}) + "\n"
|
|
4468
|
+
);
|
|
4469
|
+
} catch {
|
|
4470
|
+
finish({ ok: false, detail: "\u5199\u5165 stdin \u5931\u8D25" });
|
|
4471
|
+
}
|
|
4472
|
+
});
|
|
4473
|
+
}
|
|
4408
4474
|
async function install(client, opts) {
|
|
4409
4475
|
const claudeDir = path6.join(os2.homedir(), ".claude");
|
|
4410
4476
|
const skillDestDir = path6.join(claudeDir, "skills", "exomind");
|
|
@@ -4483,17 +4549,23 @@ async function install(client, opts) {
|
|
|
4483
4549
|
me = null;
|
|
4484
4550
|
}
|
|
4485
4551
|
}
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
console.log(dim(
|
|
4490
|
-
console.log(dim(" \u5347\u7EA7\u5B8C\u6210 \u2192 \u91CD\u542F Claude Code\uFF08skill/hook/MCP \u542F\u52A8\u65F6\u8F7D\u5165\u3001\u4E0D\u70ED\u91CD\u8F7D\uFF09\u5373\u751F\u6548"));
|
|
4491
|
-
} else if (live.api_key) {
|
|
4492
|
-
console.log(yellow(`\u5DF2\u914D\u7F6E API Key\uFF08${keyHint}\uFF09\uFF0C\u4F46\u672A\u80FD\u9A8C\u8BC1\uFF08${live.base_url}\uFF09`));
|
|
4493
|
-
console.log(dim(" \u8FD0\u884C exomind whoami \u6838\u9A8C\uFF1B\u91CD\u542F Claude Code \u2192 mcp__exomind__* \u751F\u6548"));
|
|
4552
|
+
const mcp = live.api_key ? await checkMcp() : { ok: false, detail: "\u672A\u914D\u7F6E API Key" };
|
|
4553
|
+
console.log(yellow("\n\u53EF\u7528\u6027\u81EA\u68C0:"));
|
|
4554
|
+
if (!live.api_key) {
|
|
4555
|
+
console.log(dim(" \uFF08\u672A\u914D\u7F6E API Key\uFF0C\u8DF3\u8FC7\u81EA\u68C0\uFF1Bexomind login \u540E\u91CD\u8DD1 install \u53EF\u81EA\u68C0\uFF09"));
|
|
4494
4556
|
} else {
|
|
4557
|
+
console.log(me && me.authenticated ? ok(" \u670D\u52A1\u5668\u8FDE\u901A + \u9274\u6743\u6709\u6548") : yellow(" \u2717 \u670D\u52A1\u5668\u8FDE\u901A/\u9274\u6743\u5F02\u5E38 \u2192 exomind whoami \u6838\u9A8C"));
|
|
4558
|
+
console.log(mcp.ok ? ok(` MCP \u670D\u52A1\u7AEF\u53EF\u7528\uFF08${mcp.detail}\uFF09`) : yellow(` \u2717 MCP \u670D\u52A1\u7AEF\u5F02\u5E38\uFF1A${mcp.detail}`));
|
|
4559
|
+
}
|
|
4560
|
+
console.log(yellow("\n\u4E0B\u4E00\u6B65:"));
|
|
4561
|
+
if (!live.api_key) {
|
|
4495
4562
|
console.log(dim(" 1. exomind login\uFF08\u7C98\u8D34 API Key\uFF09"));
|
|
4496
4563
|
console.log(dim(" 2. \u91CD\u542F Claude Code\uFF08\u52A0\u8F7D skill/hook/MCP\uFF09\u2192 mcp__exomind__* \u751F\u6548"));
|
|
4564
|
+
} else if (me && me.authenticated && mcp.ok) {
|
|
4565
|
+
console.log(ok(`\u51ED\u8BC1\u6709\u6548\uFF1A${live.base_url}\uFF08${keyHint}\uFF09\xB7 tenant ${me.tenant_id}`));
|
|
4566
|
+
console.log(dim(" \u81EA\u68C0\u5168\u8FC7 \u2192 \u91CD\u542F Claude Code\uFF08skill/hook/MCP \u542F\u52A8\u65F6\u8F7D\u5165\uFF09\u5373\u751F\u6548"));
|
|
4567
|
+
} else {
|
|
4568
|
+
console.log(yellow("\u81EA\u68C0\u6709\u5F02\u5E38\uFF0C\u8BF7\u6309\u4E0A\u65B9 \u2717 \u63D0\u793A\u6838\u9A8C\u540E\u518D\u91CD\u542F\u4F7F\u7528\u3002"));
|
|
4497
4569
|
}
|
|
4498
4570
|
}
|
|
4499
4571
|
|
|
@@ -4539,7 +4611,12 @@ var program2 = new Command();
|
|
|
4539
4611
|
program2.name("exomind").description("ExoMind \u8DE8\u5E73\u53F0\u77E5\u8BC6\u5E93\u5BA2\u6237\u7AEF \u2014 \u901A\u8FC7 REST \u4EA4\u4E92(\u66FF\u4EE3 Windows MCP \u5BA2\u6237\u7AEF)\u3002").version(VERSION).option("--json", "\u8F93\u51FA\u539F\u59CB JSON(\u673A\u5668\u53EF\u8BFB)").option("--base-url <url>", "\u8986\u76D6\u670D\u52A1\u5668\u5730\u5740").option("--api-key <key>", "\u8986\u76D6 API Key / \u51ED\u8BC1");
|
|
4540
4612
|
program2.command("login").description("\u914D\u7F6E\u670D\u52A1\u5668\u5730\u5740\u4E0E\u51ED\u8BC1,\u5199\u5165 ~/.exomind/config.json").option("--base-url <url>", "\u670D\u52A1\u5668\u5730\u5740").option("--api-key <key>", "API Key \u6216\u767B\u5F55 token(\u4E0D\u586B\u5219\u4EA4\u4E92\u8F93\u5165)").action(run(login));
|
|
4541
4613
|
program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u6001\u4E0E\u670D\u52A1\u5668").action(run(whoami));
|
|
4542
|
-
program2.command("ingest [content...]").description("\u5BFC\u5165\u77E5\u8BC6: \u53C2\u6570\u6587\u672C / --file / stdin / --dir \u76EE\u5F55\u6279\u91CF(\u589E\u91CF)").option("-t, --title <title>", "\u6807\u9898(\u5355\u6587\u4EF6\u6A21\u5F0F)").option("--tag <tag>", "\u6807\u7B7E(\u53EF\u91CD\u590D)", collect, []).option("--file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6\u5185\u5BB9").option("--dir <path>", "\u76EE\u5F55\u6279\u91CF\u6444\u5165(\u589E\u91CF: \u5185\u5BB9\u54C8\u5E0C\u8DF3\u8FC7\u672A\u53D8\u6587\u4EF6)").option("-r, --recursive", "\u9012\u5F52\u5B50\u76EE\u5F55(\u914D\u5408 --dir)").option("--pattern <glob>", "\u6587\u4EF6\u540D\u5339\u914D,\u9ED8\u8BA4 *.md", "*.md").option("--force", "\u5FFD\u7565 manifest,\u5F3A\u5236\u5168\u91CF\u91CD\u6444(\u914D\u5408 --dir)").
|
|
4614
|
+
program2.command("ingest [content...]").description("\u5BFC\u5165\u77E5\u8BC6: \u53C2\u6570\u6587\u672C / --file / stdin / --dir \u76EE\u5F55\u6279\u91CF(\u589E\u91CF)").option("-t, --title <title>", "\u6807\u9898(\u5355\u6587\u4EF6\u6A21\u5F0F)").option("--tag <tag>", "\u6807\u7B7E(\u53EF\u91CD\u590D)", collect, []).option("--file <path>", "\u4ECE\u6587\u4EF6\u8BFB\u53D6\u5185\u5BB9").option("--dir <path>", "\u76EE\u5F55\u6279\u91CF\u6444\u5165(\u589E\u91CF: \u5185\u5BB9\u54C8\u5E0C\u8DF3\u8FC7\u672A\u53D8\u6587\u4EF6)").option("-r, --recursive", "\u9012\u5F52\u5B50\u76EE\u5F55(\u914D\u5408 --dir)").option("--pattern <glob>", "\u6587\u4EF6\u540D\u5339\u914D,\u9ED8\u8BA4 *.md", "*.md").option("--force", "\u5FFD\u7565 manifest,\u5F3A\u5236\u5168\u91CF\u91CD\u6444(\u914D\u5408 --dir)").option(
|
|
4615
|
+
"-c, --concurrency <n>",
|
|
4616
|
+
"\u5E76\u53D1\u6444\u5165\u6570(\u914D\u5408 --dir,\u9ED8\u8BA4 3,\u5F31\u670D\u52A1\u5668\u53CB\u597D)",
|
|
4617
|
+
(v) => parseInt(v, 10) || 3,
|
|
4618
|
+
3
|
|
4619
|
+
).action(run(ingest));
|
|
4543
4620
|
program2.command("query [question...]").description("LLM \u95EE\u7B54").option("--tag <tag>", "\u6807\u7B7E\u8FC7\u6EE4(\u53EF\u91CD\u590D)", collect, []).option("--model <name>", "\u6A21\u578B").action(run(query));
|
|
4544
4621
|
program2.command("search [keyword...]").description("\u5168\u6587/\u6DF7\u5408/\u7CBE\u6392\u641C\u7D22").option("-l, --limit <n>", "\u8FD4\u56DE\u6570\u91CF", "10").option("--rerank", "LLM \u7CBE\u6392(\u66F4\u51C6\u4F46\u66F4\u6162)").option("--hybrid", "\u6DF7\u5408\u641C\u7D22(BM25+\u8BED\u4E49)").action(run(search));
|
|
4545
4622
|
program2.command("entity [name...]").description("\u5B9E\u4F53\u8BE6\u60C5 + \u5173\u7CFB").action(run(entity));
|