exomind 0.1.2 → 0.2.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 +1 -0
- package/dist/cli.js +202 -43
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +30 -0
package/README.md
CHANGED
|
@@ -26,6 +26,7 @@ exomind whoami # 验证登录
|
|
|
26
26
|
exomind ingest "Redis 持久化:RDB 快照 + AOF 日志,混合模式推荐" -t "Redis 持久化" --tag redis
|
|
27
27
|
echo "管道内容" | exomind ingest -t "标题"
|
|
28
28
|
exomind ingest --file ./notes.md -t "标题"
|
|
29
|
+
exomind ingest --dir ./notes --recursive # 目录批量(增量: SHA-256 跳过未变文件)
|
|
29
30
|
|
|
30
31
|
# 查询与搜索
|
|
31
32
|
exomind query "Redis RDB 和 AOF 的区别?"
|
package/dist/cli.js
CHANGED
|
@@ -965,8 +965,8 @@ var require_command = __commonJS({
|
|
|
965
965
|
"use strict";
|
|
966
966
|
var EventEmitter = require("events").EventEmitter;
|
|
967
967
|
var childProcess = require("child_process");
|
|
968
|
-
var
|
|
969
|
-
var
|
|
968
|
+
var path6 = require("path");
|
|
969
|
+
var fs7 = require("fs");
|
|
970
970
|
var process2 = require("process");
|
|
971
971
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
972
972
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1898,11 +1898,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1898
1898
|
let launchWithNode = false;
|
|
1899
1899
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1900
1900
|
function findFile(baseDir, baseName) {
|
|
1901
|
-
const localBin =
|
|
1902
|
-
if (
|
|
1903
|
-
if (sourceExt.includes(
|
|
1901
|
+
const localBin = path6.resolve(baseDir, baseName);
|
|
1902
|
+
if (fs7.existsSync(localBin)) return localBin;
|
|
1903
|
+
if (sourceExt.includes(path6.extname(baseName))) return void 0;
|
|
1904
1904
|
const foundExt = sourceExt.find(
|
|
1905
|
-
(ext) =>
|
|
1905
|
+
(ext) => fs7.existsSync(`${localBin}${ext}`)
|
|
1906
1906
|
);
|
|
1907
1907
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1908
1908
|
return void 0;
|
|
@@ -1914,21 +1914,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1914
1914
|
if (this._scriptPath) {
|
|
1915
1915
|
let resolvedScriptPath;
|
|
1916
1916
|
try {
|
|
1917
|
-
resolvedScriptPath =
|
|
1917
|
+
resolvedScriptPath = fs7.realpathSync(this._scriptPath);
|
|
1918
1918
|
} catch (err) {
|
|
1919
1919
|
resolvedScriptPath = this._scriptPath;
|
|
1920
1920
|
}
|
|
1921
|
-
executableDir =
|
|
1922
|
-
|
|
1921
|
+
executableDir = path6.resolve(
|
|
1922
|
+
path6.dirname(resolvedScriptPath),
|
|
1923
1923
|
executableDir
|
|
1924
1924
|
);
|
|
1925
1925
|
}
|
|
1926
1926
|
if (executableDir) {
|
|
1927
1927
|
let localFile = findFile(executableDir, executableFile);
|
|
1928
1928
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1929
|
-
const legacyName =
|
|
1929
|
+
const legacyName = path6.basename(
|
|
1930
1930
|
this._scriptPath,
|
|
1931
|
-
|
|
1931
|
+
path6.extname(this._scriptPath)
|
|
1932
1932
|
);
|
|
1933
1933
|
if (legacyName !== this._name) {
|
|
1934
1934
|
localFile = findFile(
|
|
@@ -1939,7 +1939,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1939
1939
|
}
|
|
1940
1940
|
executableFile = localFile || executableFile;
|
|
1941
1941
|
}
|
|
1942
|
-
launchWithNode = sourceExt.includes(
|
|
1942
|
+
launchWithNode = sourceExt.includes(path6.extname(executableFile));
|
|
1943
1943
|
let proc;
|
|
1944
1944
|
if (process2.platform !== "win32") {
|
|
1945
1945
|
if (launchWithNode) {
|
|
@@ -2779,7 +2779,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2779
2779
|
* @return {Command}
|
|
2780
2780
|
*/
|
|
2781
2781
|
nameFromFilename(filename) {
|
|
2782
|
-
this._name =
|
|
2782
|
+
this._name = path6.basename(filename, path6.extname(filename));
|
|
2783
2783
|
return this;
|
|
2784
2784
|
}
|
|
2785
2785
|
/**
|
|
@@ -2793,9 +2793,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2793
2793
|
* @param {string} [path]
|
|
2794
2794
|
* @return {(string|null|Command)}
|
|
2795
2795
|
*/
|
|
2796
|
-
executableDir(
|
|
2797
|
-
if (
|
|
2798
|
-
this._executableDir =
|
|
2796
|
+
executableDir(path7) {
|
|
2797
|
+
if (path7 === void 0) return this._executableDir;
|
|
2798
|
+
this._executableDir = path7;
|
|
2799
2799
|
return this;
|
|
2800
2800
|
}
|
|
2801
2801
|
/**
|
|
@@ -3119,7 +3119,7 @@ var {
|
|
|
3119
3119
|
// package.json
|
|
3120
3120
|
var package_default = {
|
|
3121
3121
|
name: "exomind",
|
|
3122
|
-
version: "0.
|
|
3122
|
+
version: "0.2.0",
|
|
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"
|
|
@@ -3165,6 +3165,10 @@ var package_default = {
|
|
|
3165
3165
|
};
|
|
3166
3166
|
|
|
3167
3167
|
// src/api.ts
|
|
3168
|
+
function opTimeout(defaultMs) {
|
|
3169
|
+
const n = Number(process.env.EXOMIND_TIMEOUT_MS);
|
|
3170
|
+
return Number.isFinite(n) && n > 0 ? n : defaultMs;
|
|
3171
|
+
}
|
|
3168
3172
|
var ApiError = class extends Error {
|
|
3169
3173
|
status;
|
|
3170
3174
|
detail;
|
|
@@ -3303,6 +3307,9 @@ function setJsonMode(v) {
|
|
|
3303
3307
|
function isJsonMode() {
|
|
3304
3308
|
return JSON_MODE;
|
|
3305
3309
|
}
|
|
3310
|
+
function hint(msg) {
|
|
3311
|
+
if (!isJsonMode()) process.stderr.write(msg + "\n");
|
|
3312
|
+
}
|
|
3306
3313
|
function output(data, pretty) {
|
|
3307
3314
|
if (JSON_MODE) {
|
|
3308
3315
|
console.log(JSON.stringify(data, null, 2));
|
|
@@ -3617,8 +3624,157 @@ async function runHook(client) {
|
|
|
3617
3624
|
}
|
|
3618
3625
|
}
|
|
3619
3626
|
|
|
3627
|
+
// src/ingest_dir.ts
|
|
3628
|
+
var fs5 = __toESM(require("fs"));
|
|
3629
|
+
var path4 = __toESM(require("path"));
|
|
3630
|
+
|
|
3631
|
+
// src/manifest.ts
|
|
3632
|
+
var fs4 = __toESM(require("fs"));
|
|
3633
|
+
var path3 = __toESM(require("path"));
|
|
3634
|
+
var crypto = __toESM(require("crypto"));
|
|
3635
|
+
var MANIFEST_FILE = path3.join(CONFIG_DIR, "manifest.json");
|
|
3636
|
+
function sha256(s) {
|
|
3637
|
+
return crypto.createHash("sha256").update(s, "utf-8").digest("hex");
|
|
3638
|
+
}
|
|
3639
|
+
function loadManifest() {
|
|
3640
|
+
try {
|
|
3641
|
+
const d = JSON.parse(fs4.readFileSync(MANIFEST_FILE, "utf-8"));
|
|
3642
|
+
return d && typeof d === "object" ? d : {};
|
|
3643
|
+
} catch {
|
|
3644
|
+
return {};
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
function saveManifest(m) {
|
|
3648
|
+
try {
|
|
3649
|
+
fs4.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
3650
|
+
fs4.writeFileSync(MANIFEST_FILE, JSON.stringify(m, null, 2));
|
|
3651
|
+
} catch {
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
function cleanupStale(m, dir, currentFiles) {
|
|
3655
|
+
const prefix = path3.resolve(dir) + path3.sep;
|
|
3656
|
+
const current = new Set(currentFiles);
|
|
3657
|
+
for (const key of Object.keys(m)) {
|
|
3658
|
+
if (key.startsWith(prefix) && !current.has(key)) {
|
|
3659
|
+
delete m[key];
|
|
3660
|
+
}
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
// src/ingest_dir.ts
|
|
3665
|
+
function globToRegex(pattern) {
|
|
3666
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
3667
|
+
return new RegExp(`^${escaped}$`);
|
|
3668
|
+
}
|
|
3669
|
+
function walkDir(dir, recursive, pattern) {
|
|
3670
|
+
const rx = globToRegex(pattern);
|
|
3671
|
+
const out = [];
|
|
3672
|
+
const walk = (d) => {
|
|
3673
|
+
let entries;
|
|
3674
|
+
try {
|
|
3675
|
+
entries = fs5.readdirSync(d, { withFileTypes: true });
|
|
3676
|
+
} catch {
|
|
3677
|
+
return;
|
|
3678
|
+
}
|
|
3679
|
+
for (const e of entries) {
|
|
3680
|
+
if (e.name.startsWith(".")) continue;
|
|
3681
|
+
const full = path4.join(d, e.name);
|
|
3682
|
+
if (e.isDirectory()) {
|
|
3683
|
+
if (recursive) walk(full);
|
|
3684
|
+
} else if (e.isFile() && rx.test(e.name)) {
|
|
3685
|
+
out.push(full);
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
};
|
|
3689
|
+
walk(path4.resolve(dir));
|
|
3690
|
+
return out.sort();
|
|
3691
|
+
}
|
|
3692
|
+
function deriveTitle(file, content) {
|
|
3693
|
+
for (const line of content.split("\n")) {
|
|
3694
|
+
const m = line.match(/^#\s+(.+?)\s*$/);
|
|
3695
|
+
if (m) return m[1].trim();
|
|
3696
|
+
}
|
|
3697
|
+
return path4.basename(file).replace(/\.[^.]+$/, "");
|
|
3698
|
+
}
|
|
3699
|
+
function planIngestest(files, manifest, force) {
|
|
3700
|
+
const toIngest = [];
|
|
3701
|
+
const toSkip = [];
|
|
3702
|
+
for (const f of files) {
|
|
3703
|
+
let content;
|
|
3704
|
+
try {
|
|
3705
|
+
content = readFileText(f);
|
|
3706
|
+
} catch {
|
|
3707
|
+
continue;
|
|
3708
|
+
}
|
|
3709
|
+
const hash = sha256(content);
|
|
3710
|
+
const prev = manifest[f];
|
|
3711
|
+
if (!force && prev && prev.hash === hash) {
|
|
3712
|
+
toSkip.push(f);
|
|
3713
|
+
} else {
|
|
3714
|
+
toIngest.push({ path: f, content, title: deriveTitle(f, content), hash });
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
return { toIngest, toSkip };
|
|
3718
|
+
}
|
|
3719
|
+
async function runDirIngestest(client, opts, dir) {
|
|
3720
|
+
const files = walkDir(dir, !!opts.recursive, opts.pattern || "*.md");
|
|
3721
|
+
if (!files.length) {
|
|
3722
|
+
console.log(dim(`\u76EE\u5F55 ${dir} \u4E0B\u65E0\u5339\u914D\u6587\u4EF6\u3002`));
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
const manifest = loadManifest();
|
|
3726
|
+
const plan = planIngestest(files, manifest, !!opts.force);
|
|
3727
|
+
const total = files.length;
|
|
3728
|
+
process.stderr.write(
|
|
3729
|
+
`\u76EE\u5F55 ${dir}: ${total} \u6587\u4EF6 \u2192 \u65B0\u589E/\u66F4\u65B0 ${plan.toIngest.length},\u8DF3\u8FC7 ${plan.toSkip.length}
|
|
3730
|
+
`
|
|
3731
|
+
);
|
|
3732
|
+
let added = 0;
|
|
3733
|
+
let updated = 0;
|
|
3734
|
+
let failed = 0;
|
|
3735
|
+
for (let i = 0; i < plan.toIngest.length; i++) {
|
|
3736
|
+
const f = plan.toIngest[i];
|
|
3737
|
+
const prev = manifest[f.path];
|
|
3738
|
+
process.stderr.write(
|
|
3739
|
+
`\u23F3 [${i + 1}/${plan.toIngest.length}] ${path4.basename(f.path)} ${prev ? "(\u66F4\u65B0)" : "(\u65B0\u589E)"}\u2026
|
|
3740
|
+
`
|
|
3741
|
+
);
|
|
3742
|
+
try {
|
|
3743
|
+
await client.post(
|
|
3744
|
+
"/ingest",
|
|
3745
|
+
{ content: f.content, title: f.title, tags: opts.tag },
|
|
3746
|
+
{ timeoutMs: opTimeout(3e5) }
|
|
3747
|
+
);
|
|
3748
|
+
manifest[f.path] = {
|
|
3749
|
+
hash: f.hash,
|
|
3750
|
+
ingested_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3751
|
+
title: f.title,
|
|
3752
|
+
size: f.content.length
|
|
3753
|
+
};
|
|
3754
|
+
if (prev) updated++;
|
|
3755
|
+
else added++;
|
|
3756
|
+
saveManifest(manifest);
|
|
3757
|
+
} catch (e) {
|
|
3758
|
+
failed++;
|
|
3759
|
+
process.stderr.write(` ${red("\u2717")} ${path4.basename(f.path)}: ${e.message}
|
|
3760
|
+
`);
|
|
3761
|
+
}
|
|
3762
|
+
}
|
|
3763
|
+
cleanupStale(manifest, dir, files);
|
|
3764
|
+
saveManifest(manifest);
|
|
3765
|
+
output(
|
|
3766
|
+
{ added, updated, skipped: plan.toSkip.length, failed, total, dir },
|
|
3767
|
+
() => console.log(
|
|
3768
|
+
green("\u2713 \u76EE\u5F55\u6444\u5165\u5B8C\u6210") + dim(
|
|
3769
|
+
`: \u65B0\u589E ${added} / \u66F4\u65B0 ${updated} / \u8DF3\u8FC7 ${plan.toSkip.length} / \u5931\u8D25 ${failed} (\u5171 ${total})`
|
|
3770
|
+
)
|
|
3771
|
+
)
|
|
3772
|
+
);
|
|
3773
|
+
}
|
|
3774
|
+
|
|
3620
3775
|
// src/commands/ingest.ts
|
|
3621
3776
|
async function ingest(client, opts, args) {
|
|
3777
|
+
if (opts.dir) return runDirIngestest(client, opts, opts.dir);
|
|
3622
3778
|
let content = "";
|
|
3623
3779
|
if (opts.file) {
|
|
3624
3780
|
content = readFileText(opts.file);
|
|
@@ -3639,9 +3795,10 @@ async function ingest(client, opts, args) {
|
|
|
3639
3795
|
const body = { content };
|
|
3640
3796
|
if (opts.title) body.title = opts.title;
|
|
3641
3797
|
if (opts.tag && opts.tag.length) body.tags = opts.tag;
|
|
3642
|
-
|
|
3798
|
+
hint("\u23F3 \u6444\u5165\u4E2D: \u670D\u52A1\u5668\u7528 LLM \u62BD\u53D6\u5B9E\u4F53/\u5173\u7CFB,\u957F\u5185\u5BB9\u53EF\u80FD 1-3 \u5206\u949F\u2026");
|
|
3799
|
+
const result = await client.post("/ingest", body, { timeoutMs: opTimeout(3e5) });
|
|
3643
3800
|
output(result, () => {
|
|
3644
|
-
console.log(ok("\u5DF2\u5BFC\u5165\u77E5\u8BC6\u5E93"));
|
|
3801
|
+
console.log(ok("\u5DF2\u5BFC\u5165\u670D\u52A1\u5668\u77E5\u8BC6\u5E93"));
|
|
3645
3802
|
if (opts.title) console.log(dim(` \u6807\u9898: ${opts.title}`));
|
|
3646
3803
|
console.log(` ${green("\u5B9E\u4F53")}: ${result.entities ?? 0} ${green("\u6982\u5FF5")}: ${result.concepts ?? 0}`);
|
|
3647
3804
|
if (result.summary) console.log(dim(` \u6458\u8981: ${truncate(result.summary, 120)}`));
|
|
@@ -3661,7 +3818,8 @@ async function query(client, opts, args) {
|
|
|
3661
3818
|
const body = { question };
|
|
3662
3819
|
if (opts.tag?.length) body.tags = opts.tag;
|
|
3663
3820
|
if (opts.model) body.model = opts.model;
|
|
3664
|
-
|
|
3821
|
+
hint("\u23F3 \u67E5\u8BE2\u4E2D: LLM \u68C0\u7D22 + \u751F\u6210,\u53EF\u80FD 1-2 \u5206\u949F\u2026");
|
|
3822
|
+
const result = await client.post("/query", body, { timeoutMs: opTimeout(18e4) });
|
|
3665
3823
|
output(result, () => {
|
|
3666
3824
|
console.log(result.answer || dim("(\u65E0\u56DE\u7B54)"));
|
|
3667
3825
|
if (result.pages?.length) {
|
|
@@ -3793,7 +3951,8 @@ async function mark(client, opts, args) {
|
|
|
3793
3951
|
async function synthesize(client, opts, args) {
|
|
3794
3952
|
const topic = args.join(" ").trim();
|
|
3795
3953
|
if (!topic) throw new Error('\u8BF7\u63D0\u4F9B\u4E3B\u9898: exomind synthesize "Redis \u6301\u4E45\u5316"');
|
|
3796
|
-
|
|
3954
|
+
hint("\u23F3 \u7EFC\u5408\u4E2D: \u591A\u6E90\u805A\u5408 + \u6D1E\u5BDF,\u53EF\u80FD 2-4 \u5206\u949F\u2026");
|
|
3955
|
+
const result = await client.post("/synthesize", { topic, depth: opts.depth ?? 2 }, { timeoutMs: opTimeout(3e5) });
|
|
3797
3956
|
output(result, () => {
|
|
3798
3957
|
console.log(bold(result.topic || topic));
|
|
3799
3958
|
if (result.content) console.log(`
|
|
@@ -3901,10 +4060,10 @@ async function login(_client, opts) {
|
|
|
3901
4060
|
)
|
|
3902
4061
|
);
|
|
3903
4062
|
}
|
|
3904
|
-
const
|
|
4063
|
+
const hint2 = token.length > 12 ? `${token.slice(0, 8)}\u2026${token.slice(-4)}` : token;
|
|
3905
4064
|
console.log(ok("\u767B\u5F55\u6210\u529F"));
|
|
3906
4065
|
console.log(dim(` \u670D\u52A1\u5668: ${baseUrl}`));
|
|
3907
|
-
console.log(dim(` \u51ED\u8BC1: ${
|
|
4066
|
+
console.log(dim(` \u51ED\u8BC1: ${hint2} (${token.startsWith("gh_") ? "GitHub token" : "API Key"})`));
|
|
3908
4067
|
}
|
|
3909
4068
|
|
|
3910
4069
|
// src/commands/whoami.ts
|
|
@@ -3920,14 +4079,14 @@ async function whoami(client) {
|
|
|
3920
4079
|
} catch {
|
|
3921
4080
|
me = {};
|
|
3922
4081
|
}
|
|
3923
|
-
const
|
|
4082
|
+
const hint2 = cfg.api_key.length > 12 ? `${cfg.api_key.slice(0, 8)}\u2026${cfg.api_key.slice(-4)}` : cfg.api_key;
|
|
3924
4083
|
const kind = cfg.api_key.startsWith("gh_") ? "GitHub token" : "API Key";
|
|
3925
4084
|
output(
|
|
3926
|
-
{ base_url: cfg.base_url, credential:
|
|
4085
|
+
{ base_url: cfg.base_url, credential: hint2, kind, ...me },
|
|
3927
4086
|
() => {
|
|
3928
4087
|
console.log(ok("\u5DF2\u767B\u5F55"));
|
|
3929
4088
|
console.log(dim(` \u670D\u52A1\u5668: ${cfg.base_url}`));
|
|
3930
|
-
console.log(dim(` \u51ED\u8BC1: ${
|
|
4089
|
+
console.log(dim(` \u51ED\u8BC1: ${hint2} (${kind})`));
|
|
3931
4090
|
if (me.authenticated) {
|
|
3932
4091
|
console.log(dim(` \u7528\u6237: ${me.name || me.login || "-"} (tenant: ${me.tenant_id || "-"})`));
|
|
3933
4092
|
}
|
|
@@ -3936,40 +4095,40 @@ async function whoami(client) {
|
|
|
3936
4095
|
}
|
|
3937
4096
|
|
|
3938
4097
|
// src/commands/install.ts
|
|
3939
|
-
var
|
|
3940
|
-
var
|
|
4098
|
+
var fs6 = __toESM(require("fs"));
|
|
4099
|
+
var path5 = __toESM(require("path"));
|
|
3941
4100
|
var os2 = __toESM(require("os"));
|
|
3942
|
-
var PKG_ROOT =
|
|
3943
|
-
var SKILL_SRC =
|
|
4101
|
+
var PKG_ROOT = path5.resolve(__dirname, "..");
|
|
4102
|
+
var SKILL_SRC = path5.join(PKG_ROOT, "skill", "SKILL.md");
|
|
3944
4103
|
function readJson2(file) {
|
|
3945
4104
|
try {
|
|
3946
|
-
return JSON.parse(
|
|
4105
|
+
return JSON.parse(fs6.readFileSync(file, "utf-8"));
|
|
3947
4106
|
} catch {
|
|
3948
4107
|
return null;
|
|
3949
4108
|
}
|
|
3950
4109
|
}
|
|
3951
4110
|
function backup(file) {
|
|
3952
|
-
if (!
|
|
4111
|
+
if (!fs6.existsSync(file)) return;
|
|
3953
4112
|
const bak = `${file}.bak-${Date.now()}`;
|
|
3954
4113
|
try {
|
|
3955
|
-
|
|
3956
|
-
console.log(dim(` (\u5DF2\u5907\u4EFD\u539F\u914D\u7F6E \u2192 ${
|
|
4114
|
+
fs6.copyFileSync(file, bak);
|
|
4115
|
+
console.log(dim(` (\u5DF2\u5907\u4EFD\u539F\u914D\u7F6E \u2192 ${path5.basename(bak)})`));
|
|
3957
4116
|
} catch {
|
|
3958
4117
|
}
|
|
3959
4118
|
}
|
|
3960
4119
|
async function install(_client, opts) {
|
|
3961
|
-
const claudeDir =
|
|
3962
|
-
const skillDestDir =
|
|
3963
|
-
if (!
|
|
4120
|
+
const claudeDir = path5.join(os2.homedir(), ".claude");
|
|
4121
|
+
const skillDestDir = path5.join(claudeDir, "skills", "exomind");
|
|
4122
|
+
if (!fs6.existsSync(SKILL_SRC)) {
|
|
3964
4123
|
throw new Error(`skill \u6E90\u4E0D\u5B58\u5728: ${SKILL_SRC}(npm \u5305\u53EF\u80FD\u635F\u574F,\u6216\u5F00\u53D1\u6A21\u5F0F\u4E0B\u672A\u6784\u5EFA)`);
|
|
3965
4124
|
}
|
|
3966
|
-
|
|
3967
|
-
|
|
4125
|
+
fs6.mkdirSync(skillDestDir, { recursive: true });
|
|
4126
|
+
fs6.copyFileSync(SKILL_SRC, path5.join(skillDestDir, "SKILL.md"));
|
|
3968
4127
|
console.log(ok("\u5DF2\u5B89\u88C5 Claude Code skill"));
|
|
3969
4128
|
console.log(dim(` \u2192 ${skillDestDir}/SKILL.md`));
|
|
3970
4129
|
if (opts.withHook) {
|
|
3971
|
-
const settingsFile =
|
|
3972
|
-
|
|
4130
|
+
const settingsFile = path5.join(claudeDir, "settings.json");
|
|
4131
|
+
fs6.mkdirSync(claudeDir, { recursive: true });
|
|
3973
4132
|
backup(settingsFile);
|
|
3974
4133
|
const settings = readJson2(settingsFile) ?? {};
|
|
3975
4134
|
const hooks = settings.hooks ?? {};
|
|
@@ -3982,7 +4141,7 @@ async function install(_client, opts) {
|
|
|
3982
4141
|
});
|
|
3983
4142
|
hooks.UserPromptSubmit = kept;
|
|
3984
4143
|
settings.hooks = hooks;
|
|
3985
|
-
|
|
4144
|
+
fs6.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + "\n");
|
|
3986
4145
|
console.log(ok("\u5DF2\u914D\u7F6E UserPromptSubmit hook \u2192 exomind hook"));
|
|
3987
4146
|
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"));
|
|
3988
4147
|
}
|
|
@@ -4033,7 +4192,7 @@ var program2 = new Command();
|
|
|
4033
4192
|
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");
|
|
4034
4193
|
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));
|
|
4035
4194
|
program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u6001\u4E0E\u670D\u52A1\u5668").action(run(whoami));
|
|
4036
|
-
program2.command("ingest [content...]").description("\u5BFC\u5165\u77E5\u8BC6: \u53C2\u6570\u6587\u672C / --file / stdin
|
|
4195
|
+
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)").action(run(ingest));
|
|
4037
4196
|
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));
|
|
4038
4197
|
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));
|
|
4039
4198
|
program2.command("entity [name...]").description("\u5B9E\u4F53\u8BE6\u60C5 + \u5173\u7CFB").action(run(entity));
|