exomind 0.3.3 → 0.3.4
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 +99 -29
- 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.4",
|
|
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"
|
|
@@ -3172,10 +3172,14 @@ function opTimeout(defaultMs) {
|
|
|
3172
3172
|
var ApiError = class extends Error {
|
|
3173
3173
|
status;
|
|
3174
3174
|
detail;
|
|
3175
|
-
|
|
3175
|
+
headers;
|
|
3176
|
+
body;
|
|
3177
|
+
constructor(status, detail, headers = {}, body = null) {
|
|
3176
3178
|
super(`HTTP ${status}: ${detail}`);
|
|
3177
3179
|
this.status = status;
|
|
3178
3180
|
this.detail = detail;
|
|
3181
|
+
this.headers = headers;
|
|
3182
|
+
this.body = body;
|
|
3179
3183
|
}
|
|
3180
3184
|
};
|
|
3181
3185
|
var ApiClient = class {
|
|
@@ -3219,13 +3223,18 @@ var ApiClient = class {
|
|
|
3219
3223
|
});
|
|
3220
3224
|
const text = await res.text();
|
|
3221
3225
|
if (!res.ok) {
|
|
3226
|
+
const headers = {};
|
|
3227
|
+
res.headers?.forEach((v, k) => {
|
|
3228
|
+
headers[k.toLowerCase()] = v;
|
|
3229
|
+
});
|
|
3222
3230
|
let detail = text || res.statusText;
|
|
3231
|
+
let body = null;
|
|
3223
3232
|
try {
|
|
3224
|
-
|
|
3225
|
-
detail =
|
|
3233
|
+
body = JSON.parse(text);
|
|
3234
|
+
detail = body.detail || body.message || JSON.stringify(body);
|
|
3226
3235
|
} catch {
|
|
3227
3236
|
}
|
|
3228
|
-
throw new ApiError(res.status, String(detail).slice(0, 800));
|
|
3237
|
+
throw new ApiError(res.status, String(detail).slice(0, 800), headers, body);
|
|
3229
3238
|
}
|
|
3230
3239
|
if (opts.text) return text;
|
|
3231
3240
|
try {
|
|
@@ -3881,6 +3890,55 @@ function planIngestest(files, manifest, force) {
|
|
|
3881
3890
|
}
|
|
3882
3891
|
return { toIngest, toSkip };
|
|
3883
3892
|
}
|
|
3893
|
+
var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
3894
|
+
var suspended = false;
|
|
3895
|
+
async function ingestWithRetry(client, payload, timeoutMs) {
|
|
3896
|
+
let rateAttempts = 0;
|
|
3897
|
+
let quotaWaits = 0;
|
|
3898
|
+
while (true) {
|
|
3899
|
+
try {
|
|
3900
|
+
return await client.post("/ingest", payload, { timeoutMs });
|
|
3901
|
+
} catch (e) {
|
|
3902
|
+
if (!(e instanceof ApiError) || e.status !== 429) throw e;
|
|
3903
|
+
const type = e.body?.type;
|
|
3904
|
+
if (type === "daily_quota") {
|
|
3905
|
+
if (++quotaWaits > 3) throw new ApiError(429, "\u914D\u989D\u8FDE\u7EED 3 \u4E2A\u81EA\u7136\u65E5\u672A\u6062\u590D,\u653E\u5F03");
|
|
3906
|
+
await suspendUntilMidnight(Number(e.body?.reset ?? 0));
|
|
3907
|
+
continue;
|
|
3908
|
+
}
|
|
3909
|
+
if (type === "rate_limit") {
|
|
3910
|
+
if (++rateAttempts >= 5) throw new ApiError(429, "\u5E76\u53D1\u9650\u6D41,\u91CD\u8BD5 5 \u6B21\u4ECD\u5931\u8D25");
|
|
3911
|
+
const retry = Number(e.headers["retry-after"] ?? e.body?.retry_after ?? 5);
|
|
3912
|
+
process.stderr.write(dim(` \u23F8 \u5E76\u53D1\u9650\u6D41,${retry}s \u540E\u91CD\u8BD5
|
|
3913
|
+
`));
|
|
3914
|
+
await sleep(retry * 1e3);
|
|
3915
|
+
continue;
|
|
3916
|
+
}
|
|
3917
|
+
throw e;
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
async function suspendUntilMidnight(resetEpoch) {
|
|
3922
|
+
suspended = true;
|
|
3923
|
+
const now = Date.now();
|
|
3924
|
+
const waitMs = resetEpoch > 0 ? Math.max(1e3, resetEpoch * 1e3 - now) : 60 * 1e3;
|
|
3925
|
+
process.stderr.write(
|
|
3926
|
+
dim(` \u23F8 \u4ECA\u65E5\u914D\u989D\u5DF2\u6EE1,\u6302\u8D77\u5230\u6B21\u65E5 0 \u70B9\u7EED\u8DD1(\u7EA6 ${Math.ceil(waitMs / 6e4)} \u5206\u949F)
|
|
3927
|
+
`)
|
|
3928
|
+
);
|
|
3929
|
+
process.stderr.write(dim(" Ctrl+C \u53EF\u5B89\u5168\u9000\u51FA(\u5DF2\u4FDD\u5B58\u8FDB\u5EA6),\u6B21\u65E5\u91CD\u8DD1\u540C\u547D\u4EE4\u5373\u53EF\u7EED\u8DD1\n"));
|
|
3930
|
+
const start = Date.now();
|
|
3931
|
+
while (Date.now() - start < waitMs) {
|
|
3932
|
+
const remaining = waitMs - (Date.now() - start);
|
|
3933
|
+
await sleep(Math.min(6e4, remaining));
|
|
3934
|
+
const remainMin = Math.ceil((waitMs - (Date.now() - start)) / 6e4);
|
|
3935
|
+
if (remainMin > 0) process.stderr.write(`\r ${dim(`\u5269\u4F59\u7EA6 ${remainMin} \u5206\u949F`)} `);
|
|
3936
|
+
}
|
|
3937
|
+
process.stderr.write(`
|
|
3938
|
+
${dim("\u5230\u8FBE 0 \u70B9,\u7EE7\u7EED\u6444\u5165\u2026")}
|
|
3939
|
+
`);
|
|
3940
|
+
suspended = false;
|
|
3941
|
+
}
|
|
3884
3942
|
async function runDirIngestest(client, opts, dir) {
|
|
3885
3943
|
const files = walkDir(dir, !!opts.recursive, opts.pattern || "*.md");
|
|
3886
3944
|
if (!files.length) {
|
|
@@ -3894,39 +3952,51 @@ async function runDirIngestest(client, opts, dir) {
|
|
|
3894
3952
|
`\u76EE\u5F55 ${dir}: ${total} \u6587\u4EF6 \u2014 \u5F85\u6444\u5165 ${plan.toIngest.length},\u8DF3\u8FC7 ${plan.toSkip.length}
|
|
3895
3953
|
`
|
|
3896
3954
|
);
|
|
3955
|
+
const onSigInt = () => {
|
|
3956
|
+
if (suspended) {
|
|
3957
|
+
saveManifest(manifest);
|
|
3958
|
+
process.stderr.write("\n\u5DF2\u4FDD\u5B58\u8FDB\u5EA6,\u9000\u51FA\u3002\u6B21\u65E5\u91CD\u8DD1\u540C\u547D\u4EE4\u5373\u53EF\u7EED\u8DD1\u3002\n");
|
|
3959
|
+
}
|
|
3960
|
+
process.exit(130);
|
|
3961
|
+
};
|
|
3962
|
+
process.on("SIGINT", onSigInt);
|
|
3897
3963
|
let added = 0;
|
|
3898
3964
|
let updated = 0;
|
|
3899
3965
|
let failed = 0;
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3966
|
+
try {
|
|
3967
|
+
for (let i = 0; i < plan.toIngest.length; i++) {
|
|
3968
|
+
const f = plan.toIngest[i];
|
|
3969
|
+
const prev = manifest[f.path];
|
|
3970
|
+
process.stderr.write(`\u23F3 [${i + 1}/${plan.toIngest.length}] ${path4.basename(f.path)}\u2026
|
|
3904
3971
|
`);
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3972
|
+
try {
|
|
3973
|
+
const res = await ingestWithRetry(
|
|
3974
|
+
client,
|
|
3975
|
+
{ content: f.content, title: f.title, tags: opts.tag },
|
|
3976
|
+
opTimeout(3e5)
|
|
3977
|
+
);
|
|
3978
|
+
recordFile(manifest, f.path, f.content, f.title);
|
|
3979
|
+
saveManifest(manifest);
|
|
3980
|
+
if (prev) {
|
|
3981
|
+
updated++;
|
|
3982
|
+
process.stderr.write(` ${green("\u2713")} \u66F4\u65B0 \u2014 \u5B9E\u4F53 ${res.entities ?? 0}/\u6982\u5FF5 ${res.concepts ?? 0}
|
|
3916
3983
|
`);
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3984
|
+
} else {
|
|
3985
|
+
added++;
|
|
3986
|
+
process.stderr.write(` ${green("\u2713")} \u65B0\u589E \u2014 \u5B9E\u4F53 ${res.entities ?? 0}/\u6982\u5FF5 ${res.concepts ?? 0}
|
|
3920
3987
|
`);
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3988
|
+
}
|
|
3989
|
+
} catch (e) {
|
|
3990
|
+
failed++;
|
|
3991
|
+
process.stderr.write(` ${red("\u2717")} ${e.message}
|
|
3925
3992
|
`);
|
|
3993
|
+
}
|
|
3926
3994
|
}
|
|
3995
|
+
cleanupStale(manifest, dir, files);
|
|
3996
|
+
saveManifest(manifest);
|
|
3997
|
+
} finally {
|
|
3998
|
+
process.removeListener("SIGINT", onSigInt);
|
|
3927
3999
|
}
|
|
3928
|
-
cleanupStale(manifest, dir, files);
|
|
3929
|
-
saveManifest(manifest);
|
|
3930
4000
|
const allUpToDate = added + updated === 0 && plan.toSkip.length > 0 && failed === 0;
|
|
3931
4001
|
output(
|
|
3932
4002
|
{ added, updated, skipped: plan.toSkip.length, failed, total, dir, allUpToDate },
|