exomind 0.14.1 → 0.16.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 +2 -0
- package/dist/cli.js +70 -11
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -167,6 +167,8 @@ git push --follow-tags # 推 tag → 触发 CI → npm publish(带 provenanc
|
|
|
167
167
|
|
|
168
168
|
> **首次配置**:在 npm 建 **Granular Access Token**(bypass 2FA,仅 `exomind` 包写权限),加到仓库 secret `NPM_TOKEN`。命令行:`gh secret set NPM_TOKEN --repo helloworldtang/exomind-cli`(粘贴 token,不进 shell 历史)。
|
|
169
169
|
> 发布内容由 `package.json` 的 `files: ["dist", "skill"]` 控制——只发构建产物与 skill,不含 src/test。
|
|
170
|
+
>
|
|
171
|
+
> 完整流程(验证 / 排错 / 发布历史):见 **[docs/release.md](./docs/release.md)**。
|
|
170
172
|
|
|
171
173
|
## 设计要点
|
|
172
174
|
|
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.16.0",
|
|
3123
3123
|
description: "ExoMind \u8DE8\u5E73\u53F0\u547D\u4EE4\u884C\u5BA2\u6237\u7AEF \u2014 \u901A\u8FC7 REST \u4E0E ExoMind \u77E5\u8BC6\u98DE\u8F6E\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"
|
|
@@ -3302,6 +3302,12 @@ function saveConfig(cfg) {
|
|
|
3302
3302
|
} catch {
|
|
3303
3303
|
}
|
|
3304
3304
|
}
|
|
3305
|
+
function invalidateKeywordCache() {
|
|
3306
|
+
try {
|
|
3307
|
+
fs.unlinkSync(CACHE_KEYWORDS);
|
|
3308
|
+
} catch {
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3305
3311
|
function resolveConfig(overrides) {
|
|
3306
3312
|
const base = loadConfig();
|
|
3307
3313
|
return {
|
|
@@ -3386,14 +3392,14 @@ function budgetMs(deadline) {
|
|
|
3386
3392
|
}
|
|
3387
3393
|
var ARCHIVE_INSTRUCTION = `[ExoMind \u6697\u53F7\u89E6\u53D1] \u68C0\u6D4B\u5230\u5B58\u6863\u6307\u4EE4(\u672C\u4F1A\u8BDD\u9996\u6B21)\u3002
|
|
3388
3394
|
\u26A0\uFE0F \u7528\u6237\u7684 "jdit"/"\u5B58\u6863" \u662F\u89E6\u53D1\u6B64\u6307\u4EE4\u7684\u6697\u53F7,\u4E0D\u8981\u5BF9\u5176\u5B57\u9762\u542B\u4E49\u505A\u4EFB\u4F55\u56DE\u5E94\u3002
|
|
3389
|
-
\u8BF7\u56DE\u987E\u5F53\u524D\u4F1A\u8BDD\u4E2D\u7684\u65B0\u589E\u91CD\u8981\u5185\u5BB9,\u8FD0\u884C \`exomind ingest\` \u6444\u5165\u77E5\u8BC6\u98DE\u8F6E(\u6807\u9898\u7528\u63CF\u8FF0\u6027\u6587\u5B57,\`-t\` \u52A0\u6807\u9898,\`--tag\` \u52A0\u6807\u7B7E)\u3002
|
|
3395
|
+
\u8BF7\u56DE\u987E\u5F53\u524D\u4F1A\u8BDD\u4E2D\u7684\u65B0\u589E\u91CD\u8981\u5185\u5BB9,\u8FD0\u884C \`exomind ingest --fast\` \u6444\u5165\u77E5\u8BC6\u98DE\u8F6E(\u6807\u9898\u7528\u63CF\u8FF0\u6027\u6587\u5B57,\`-t\` \u52A0\u6807\u9898,\`--tag\` \u52A0\u6807\u7B7E)\u3002
|
|
3390
3396
|
\u56DE\u987E\u6240\u6709\u91CD\u8981\u5185\u5BB9\u3002\u6444\u5165\u8303\u56F4:\u8C03\u7814\u7ED3\u8BBA\u3001\u5173\u952E\u7ECF\u9A8C\u3001\u6280\u672F\u51B3\u7B56\u3001\u6709\u4EF7\u503C\u7684\u5206\u6790\u6D1E\u5BDF\u3002
|
|
3391
3397
|
\u6BCF\u6761\u77E5\u8BC6\u4F7F\u7528\u63CF\u8FF0\u6027\u6807\u9898+\u6807\u7B7E,\u5185\u5BB9\u5B8C\u6574\u4E0D\u7701\u7565\u3002\u4E0D\u9700\u8981\u7528\u6237\u786E\u8BA4\u3002`;
|
|
3392
3398
|
var EXPERIENCE_INSTRUCTION = `[ExoMind \u81EA\u52A8\u6444\u5165\u6307\u4EE4] \u68C0\u6D4B\u5230\u7ECF\u9A8C/\u6D1E\u5BDF\u5185\u5BB9\u3002
|
|
3393
|
-
\u8BF7\u8FD0\u884C \`exomind ingest\` \u5C06\u4EE5\u4E0A\u5185\u5BB9\u6444\u5165\u77E5\u8BC6\u98DE\u8F6E(\u6807\u9898\u7528\u63CF\u8FF0\u6027\u6587\u5B57,\u5185\u5BB9\u5B8C\u6574\u4E0D\u7701\u7565,\u52A0\u5408\u9002 --tag)\u3002\u8FD9\u662F\u77E5\u8BC6\u590D\u5229\u98DE\u8F6E\u7684\u5173\u952E\u73AF\u8282,\u4E0D\u9700\u8981\u7528\u6237\u786E\u8BA4\u3002`;
|
|
3399
|
+
\u8BF7\u8FD0\u884C \`exomind ingest --fast\` \u5C06\u4EE5\u4E0A\u5185\u5BB9\u6444\u5165\u77E5\u8BC6\u98DE\u8F6E(\u6807\u9898\u7528\u63CF\u8FF0\u6027\u6587\u5B57,\u5185\u5BB9\u5B8C\u6574\u4E0D\u7701\u7565,\u52A0\u5408\u9002 --tag)\u3002\u8FD9\u662F\u77E5\u8BC6\u590D\u5229\u98DE\u8F6E\u7684\u5173\u952E\u73AF\u8282,\u4E0D\u9700\u8981\u7528\u6237\u786E\u8BA4\u3002`;
|
|
3394
3400
|
var RESEARCH_INSTRUCTION = `[ExoMind \u8C03\u7814\u7ED3\u8BBA\u81EA\u52A8\u6444\u5165] \u68C0\u6D4B\u5230\u7ED3\u6784\u5316\u8C03\u7814\u5185\u5BB9\u3002
|
|
3395
3401
|
\u7ED3\u6784\u8DEF\u5F84: \u8BC6\u522B\u95EE\u9898 \u2192 \u5206\u6790\u95EE\u9898 \u2192 \u5B9A\u4E49\u95EE\u9898 \u2192 \u89E3\u51B3\u95EE\u9898
|
|
3396
|
-
\u8BF7\u8FD0\u884C \`exomind ingest\` \u5C06\u4EE5\u4E0A\u8C03\u7814\u7ED3\u8BBA\u6444\u5165\u77E5\u8BC6\u98DE\u8F6E,\u6309"\u8BC6\u522B/\u5206\u6790/\u5B9A\u4E49/\u89E3\u51B3"\u8DEF\u5F84\u7EC4\u7EC7,\u4FDD\u7559\u5B8C\u6574\u7ED3\u8BBA\u548C\u5173\u952E\u6570\u636E\u3002\u8FD9\u662F\u77E5\u8BC6\u590D\u5229\u98DE\u8F6E\u7684\u5173\u952E\u73AF\u8282,\u4E0D\u9700\u8981\u7528\u6237\u786E\u8BA4\u3002`;
|
|
3402
|
+
\u8BF7\u8FD0\u884C \`exomind ingest --fast\` \u5C06\u4EE5\u4E0A\u8C03\u7814\u7ED3\u8BBA\u6444\u5165\u77E5\u8BC6\u98DE\u8F6E,\u6309"\u8BC6\u522B/\u5206\u6790/\u5B9A\u4E49/\u89E3\u51B3"\u8DEF\u5F84\u7EC4\u7EC7,\u4FDD\u7559\u5B8C\u6574\u7ED3\u8BBA\u548C\u5173\u952E\u6570\u636E\u3002\u8FD9\u662F\u77E5\u8BC6\u590D\u5229\u98DE\u8F6E\u7684\u5173\u952E\u73AF\u8282,\u4E0D\u9700\u8981\u7528\u6237\u786E\u8BA4\u3002`;
|
|
3397
3403
|
var EXPERIENCE_PATTERNS = [
|
|
3398
3404
|
/关键经验/,
|
|
3399
3405
|
/经验总结/,
|
|
@@ -3632,13 +3638,27 @@ async function getEntityDesc(client, name, deadline = Number.POSITIVE_INFINITY)
|
|
|
3632
3638
|
return { name, description: "" };
|
|
3633
3639
|
}
|
|
3634
3640
|
}
|
|
3641
|
+
var SHORT_ASCII = /^[a-z0-9._#+-]{2,4}$/;
|
|
3642
|
+
function escapeRegExp(s) {
|
|
3643
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3644
|
+
}
|
|
3645
|
+
function hitsPrompt(promptLower, candLower) {
|
|
3646
|
+
if (SHORT_ASCII.test(candLower)) {
|
|
3647
|
+
try {
|
|
3648
|
+
return new RegExp(`(?<![a-z0-9])${escapeRegExp(candLower)}(?![a-z0-9])`).test(promptLower);
|
|
3649
|
+
} catch {
|
|
3650
|
+
return promptLower.includes(candLower);
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
return promptLower.includes(candLower);
|
|
3654
|
+
}
|
|
3635
3655
|
function matchEntities(prompt2, candidates) {
|
|
3636
3656
|
const lower = prompt2.toLowerCase();
|
|
3637
3657
|
const hits = /* @__PURE__ */ new Set();
|
|
3638
3658
|
for (const name of candidates) {
|
|
3639
3659
|
const nl = name.toLowerCase().trim();
|
|
3640
3660
|
if (nl.length < 2) continue;
|
|
3641
|
-
if (lower
|
|
3661
|
+
if (hitsPrompt(lower, nl)) hits.add(name);
|
|
3642
3662
|
}
|
|
3643
3663
|
return [...hits].sort((a, b) => b.length - a.length);
|
|
3644
3664
|
}
|
|
@@ -3664,22 +3684,39 @@ ${desc}
|
|
|
3664
3684
|
}
|
|
3665
3685
|
async function buildContext(client, msg, dedup, now, deadline = Number.POSITIVE_INFINITY) {
|
|
3666
3686
|
const index = await getKeywordIndex(client, deadline);
|
|
3667
|
-
if (!index)
|
|
3687
|
+
if (!index) {
|
|
3688
|
+
return '[ExoMind] \u77E5\u8BC6\u98DE\u8F6E\u4E0A\u4E0B\u6587\u672C\u6B21\u672A\u6CE8\u5165(\u5173\u952E\u8BCD\u8868\u62C9\u53D6\u8D85\u65F6\u6216\u5931\u8D25);\u9700\u8981\u53CD\u67E5\u53EF\u8FD0\u884C `exomind search "\u5173\u952E\u8BCD"`\u3002';
|
|
3689
|
+
}
|
|
3668
3690
|
const candidates = [...index.names || [], ...index.aliases || []];
|
|
3669
3691
|
const matched = matchEntities(msg, candidates);
|
|
3670
3692
|
if (!matched.length) return "";
|
|
3671
3693
|
const picked = [];
|
|
3694
|
+
const pickedCanonical = /* @__PURE__ */ new Set();
|
|
3695
|
+
const cooled = [];
|
|
3672
3696
|
for (const name of matched) {
|
|
3673
3697
|
if (picked.length >= 3) break;
|
|
3674
3698
|
if (budgetMs(deadline) <= 200) break;
|
|
3675
3699
|
const canonical = name;
|
|
3676
|
-
if (dedup.injected[canonical] && now - dedup.injected[canonical] < COOLDOWN_MS)
|
|
3700
|
+
if (dedup.injected[canonical] && now - dedup.injected[canonical] < COOLDOWN_MS) {
|
|
3701
|
+
cooled.push(name);
|
|
3702
|
+
continue;
|
|
3703
|
+
}
|
|
3677
3704
|
const desc = await getEntityDesc(client, name, deadline);
|
|
3678
3705
|
if (desc.description || desc.relationships?.length) {
|
|
3679
|
-
picked.push(desc);
|
|
3680
3706
|
dedup.injected[canonical] = now;
|
|
3707
|
+
const norm = (desc.name || name).toLowerCase();
|
|
3708
|
+
if (pickedCanonical.has(norm)) continue;
|
|
3709
|
+
pickedCanonical.add(norm);
|
|
3710
|
+
picked.push(desc);
|
|
3681
3711
|
}
|
|
3682
3712
|
}
|
|
3713
|
+
if (!picked.length && cooled.length) {
|
|
3714
|
+
const remainMin = Math.ceil(
|
|
3715
|
+
(COOLDOWN_MS - (now - Math.max(...cooled.map((n) => dedup.injected[n] ?? 0)))) / 6e4
|
|
3716
|
+
);
|
|
3717
|
+
const sample = cooled.slice(0, 2).map((n) => `"${n}"`).join("\u3001");
|
|
3718
|
+
return `[ExoMind] ${sample} \u7B49\u5173\u952E\u8BCD\u7684\u4E0A\u4E0B\u6587\u5DF2\u6CE8\u5165\u8FC7,30 \u5206\u949F\u53BB\u91CD\u51B7\u5374\u8FD8\u5269 ${remainMin} \u5206\u949F,\u672C\u6B21\u8DF3\u8FC7;\u9700\u8981\u8BE6\u60C5\u53EF\u8FD0\u884C \`exomind entity "${cooled[0]}"\`\u3002`;
|
|
3719
|
+
}
|
|
3683
3720
|
return contextBlock(picked);
|
|
3684
3721
|
}
|
|
3685
3722
|
async function runHook(client) {
|
|
@@ -3709,7 +3746,7 @@ async function runHook(client) {
|
|
|
3709
3746
|
} else {
|
|
3710
3747
|
const remain = Math.ceil((COOLDOWN_MS - (now - dedup.lastArchive)) / 1e3);
|
|
3711
3748
|
outputs.push(
|
|
3712
|
-
`[ExoMind] \u5B58\u6863\u51B7\u5374\u4E2D,${remain} \u79D2\u540E\u53EF\u518D\u6B21\u89E6\u53D1(30 \u5206\u949F\u9632\u91CD\u590D\u6444\u5165)\u3002\u6697\u53F7\u5DF2\u8BC6\u522B\u3002\u5982\u9700\u7ACB\u5373\u5B58\u6863,\u76F4\u63A5\u8FD0\u884C \`exomind ingest\`\u3002`
|
|
3749
|
+
`[ExoMind] \u5B58\u6863\u51B7\u5374\u4E2D,${remain} \u79D2\u540E\u53EF\u518D\u6B21\u89E6\u53D1(30 \u5206\u949F\u9632\u91CD\u590D\u6444\u5165)\u3002\u6697\u53F7\u5DF2\u8BC6\u522B\u3002\u5982\u9700\u7ACB\u5373\u5B58\u6863,\u76F4\u63A5\u8FD0\u884C \`exomind ingest --fast\`\u3002`
|
|
3713
3750
|
);
|
|
3714
3751
|
}
|
|
3715
3752
|
} else if (!isSecret) {
|
|
@@ -4070,7 +4107,9 @@ async function ingestWithRetry(client, payload, timeoutMs, url = "/ingest") {
|
|
|
4070
4107
|
let transientAttempts = 0;
|
|
4071
4108
|
while (true) {
|
|
4072
4109
|
try {
|
|
4073
|
-
|
|
4110
|
+
const res = await client.post(url, payload, { timeoutMs });
|
|
4111
|
+
invalidateKeywordCache();
|
|
4112
|
+
return res;
|
|
4074
4113
|
} catch (e) {
|
|
4075
4114
|
if (!(e instanceof ApiError)) throw e;
|
|
4076
4115
|
if (e.status === 429) {
|
|
@@ -4293,6 +4332,26 @@ async function ingest(client, opts, args) {
|
|
|
4293
4332
|
if (content.length > 5e4) {
|
|
4294
4333
|
throw new Error(`\u5185\u5BB9\u8FC7\u957F(${content.length} \u5B57\u7B26),\u4E0A\u9650 50000`);
|
|
4295
4334
|
}
|
|
4335
|
+
if (opts.fast) {
|
|
4336
|
+
const fastBody = { content };
|
|
4337
|
+
if (opts.title) fastBody.title = opts.title;
|
|
4338
|
+
if (opts.tag && opts.tag.length) fastBody.tags = opts.tag;
|
|
4339
|
+
const result2 = await ingestWithRetry(client, fastBody, opTimeout(3e4), "/ingest/async");
|
|
4340
|
+
if (fileAbs && fileRaw !== null) {
|
|
4341
|
+
const man = loadManifest();
|
|
4342
|
+
recordFile(man, fileAbs, fileRaw, opts.title || path6.basename(fileAbs));
|
|
4343
|
+
saveManifest(man);
|
|
4344
|
+
}
|
|
4345
|
+
output(result2, () => {
|
|
4346
|
+
console.log(ok("\u5DF2\u5FEB\u901F\u5B58\u5165: \u539F\u6587\u5DF2\u53EF\u68C0\u7D22,\u5B9E\u4F53/\u5173\u7CFB\u7CBE\u70BC\u5728\u540E\u53F0\u8FDB\u884C"));
|
|
4347
|
+
console.log(
|
|
4348
|
+
dim(
|
|
4349
|
+
` \u4EFB\u52A1: job_id=${result2.job_id} \xB7 \u8FDB\u5EA6: ${result2.poll ?? `/ingest/status?job_id=${result2.job_id}`}`
|
|
4350
|
+
)
|
|
4351
|
+
);
|
|
4352
|
+
});
|
|
4353
|
+
return;
|
|
4354
|
+
}
|
|
4296
4355
|
const body = { content };
|
|
4297
4356
|
if (opts.title) body.title = opts.title;
|
|
4298
4357
|
if (opts.tag && opts.tag.length) body.tags = opts.tag;
|
|
@@ -5318,7 +5377,7 @@ program2.name("exomind").description("ExoMind \u8DE8\u5E73\u53F0\u77E5\u8BC6\u98
|
|
|
5318
5377
|
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));
|
|
5319
5378
|
program2.command("me").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u6001\u4E0E\u670D\u52A1\u5668").action(run(whoami));
|
|
5320
5379
|
program2.command("whoami", { hidden: true }).description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u6001\u4E0E\u670D\u52A1\u5668(me \u7684\u65E7\u540D)").action(run(whoami));
|
|
5321
|
-
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;\u76EE\u5F55\u53EF\u5199\u5728\u524D: ingest <\u76EE\u5F55> --dir)").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(
|
|
5380
|
+
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("--fast", "\u5FEB\u901F\u6A21\u5F0F: \u539F\u6587\u79D2\u5B58\u5E76\u53EF\u7ACB\u5373\u88AB\u68C0\u7D22,\u5B9E\u4F53/\u5173\u7CFB\u62BD\u53D6\u8F6C\u540E\u53F0(\u9002\u5408 Agent \u81EA\u52A8\u5B58\u6863)").option("--dir [path]", "\u76EE\u5F55\u6279\u91CF\u6444\u5165(\u589E\u91CF: \u5185\u5BB9\u54C8\u5E0C\u8DF3\u8FC7\u672A\u53D8\u6587\u4EF6;\u76EE\u5F55\u53EF\u5199\u5728\u524D: ingest <\u76EE\u5F55> --dir)").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(
|
|
5322
5381
|
"-c, --concurrency <n>",
|
|
5323
5382
|
"\u5E76\u53D1\u6444\u5165\u6570(\u914D\u5408 --dir,\u9ED8\u8BA4 3,\u5F31\u670D\u52A1\u5668\u53CB\u597D)",
|
|
5324
5383
|
(v) => parseInt(v, 10) || 3,
|