exomind 0.17.0 → 0.17.2

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 CHANGED
@@ -7,17 +7,17 @@
7
7
  - **跨平台**:纯 Node,Windows PowerShell / macOS / Linux 行为完全一致,无需 Git Bash / Python / curl。
8
8
  - **零运行时依赖**:`commander` / `picocolors` 由 tsup 打进单文件,基于 Node 18+ 全局 `fetch`。
9
9
  - **服务器零改动**:命令与服务端 REST 端点 1:1,认证走 `Authorization: Bearer`。
10
- - **自带飞轮**:`exomind hook` 子命令跨平台复刻旧 bash hook(存档暗号 / 经验·调研自动摄入 / 关键词上下文注入)。
10
+ - **自带飞轮**:`emcli hook` 子命令跨平台复刻旧 bash hook(存档暗号 / 经验·调研自动摄入 / 关键词上下文注入)。
11
11
 
12
12
  ## 安装
13
13
 
14
14
  ```bash
15
15
  npm install -g exomind
16
- exomind login # 粘贴 youhuale.cn/ui/account 的 API Key
17
- exomind me # 验证登录
16
+ emcli login # 粘贴 youhuale.cn/ui/account 的 API Key
17
+ emcli me # 验证登录
18
18
  ```
19
19
 
20
- > **短命令**:`emcli` 是同一入口的别名(`exomind` 太长时的省敲方案),`emcli query "..."` 等价于 `exomind query "..."`,help/usage 会跟随实际调用名。两个名字同时可用;文档示例一律写 `exomind`。
20
+ > **命令名**:npm 包名是 `exomind`,装出的 CLI 有两个等价命令名(bin 双名同入口):本 README 示例统一用 `emcli`,敲 `exomind` 完全等价。
21
21
 
22
22
  > 前置:Node.js 18+(`node -v`)。CI 等场景可改用环境变量 `EXOMIND_API_KEY` / `EXOMIND_BASE_URL`,免登录。
23
23
 
@@ -25,55 +25,55 @@ exomind me # 验证登录
25
25
 
26
26
  ```bash
27
27
  # 导入知识(参数 / stdin / 文件)
28
- exomind ingest "Redis 持久化:RDB 快照 + AOF 日志,混合模式推荐" -t "Redis 持久化" --tag redis
29
- echo "管道内容" | exomind ingest -t "标题"
30
- exomind ingest --file ./notes.md -t "标题"
31
- exomind ingest --dir ./notes --recursive # 目录批量(增量: SHA-256 跳过未变文件)
28
+ emcli ingest "Redis 持久化:RDB 快照 + AOF 日志,混合模式推荐" -t "Redis 持久化" --tag redis
29
+ echo "管道内容" | emcli ingest -t "标题"
30
+ emcli ingest --file ./notes.md -t "标题"
31
+ emcli ingest --dir ./notes --recursive # 目录批量(增量: SHA-256 跳过未变文件)
32
32
 
33
33
  # 查询与搜索
34
- exomind query "Redis RDB 和 AOF 的区别?"
35
- exomind search "Redis 持久化" --rerank
36
- exomind entity "Redis" # 实体详情 + 关系
37
- exomind stats # 知识飞轮统计
34
+ emcli query "Redis RDB 和 AOF 的区别?"
35
+ emcli search "Redis 持久化" --rerank
36
+ emcli entity "Redis" # 实体详情 + 关系
37
+ emcli stats # 知识飞轮统计
38
38
 
39
39
  # 飞轮
40
- exomind review # FSRS-5 间隔复习
41
- exomind gaps # 知识缺口(驱动摄入)
42
- exomind feedback "entities/Redis.md" positive
40
+ emcli review # FSRS-5 间隔复习
41
+ emcli gaps # 知识缺口(驱动摄入)
42
+ emcli feedback "entities/Redis.md" positive
43
43
  ```
44
44
 
45
- 加 `--json` 获取机器可读输出(脚本/管道):`exomind --json stats | jq .total_nodes`。
45
+ 加 `--json` 获取机器可读输出(脚本/管道):`emcli --json stats | jq .total_nodes`。
46
46
 
47
47
  ## 凭证管理
48
48
 
49
- `exomind login` 输入的凭证持久化到本地,后续命令自动读取,无需重复登录。
49
+ `emcli login` 输入的凭证持久化到本地,后续命令自动读取,无需重复登录。
50
50
 
51
51
  - **存储位置**:`~/.exomind/config.json`(明文 JSON),文件权限 `0600`(仅所有者可读写;Windows 无 POSIX 权限则忽略)。
52
52
  - **凭证类型**:服务端 `auth_middleware` 同时接受 **API Key**(从 `youhuale.cn/ui/account` 复制)与 **GitHub token**(`gh_` 前缀);两者统一以 `Authorization: Bearer` 发送,CLI 不关心是哪种。
53
53
  - **读取优先级**:`config.json` 的 `api_key` → 环境变量 `EXOMIND_API_KEY` → 旧版遗留文件 `~/.claude/scripts/.exomind-api-key`(向后兼容老安装)。三者任一存在即免登录。
54
54
  - **CI / 免登录**:只设环境变量 `EXOMIND_API_KEY`(可选 `EXOMIND_BASE_URL`)即可,完全不写本地文件。`config.json` 优先级高于环境变量,故已 `login` 的机器需 `--api-key` 才能临时覆盖。
55
- - **校验行为**:`login` 先探活 `/keywords` **通过后再落盘**——401/403 时**不写文件**,避免无效凭证覆盖已有有效配置;网络错误无法判定时仍保存并提示"登录成功(未校验)",稍后用 `exomind me` 复核。
56
- - **换号 / 登出**:重新 `exomind login` 覆盖旧凭证;彻底登出删 `~/.exomind/config.json`。
55
+ - **校验行为**:`login` 先探活 `/keywords` **通过后再落盘**——401/403 时**不写文件**,避免无效凭证覆盖已有有效配置;网络错误无法判定时仍保存并提示"登录成功(未校验)",稍后用 `emcli me` 复核。
56
+ - **换号 / 登出**:重新 `emcli login` 覆盖旧凭证;彻底登出删 `~/.exomind/config.json`。
57
57
  - **安全提醒**:文件是**明文**,任何能读你 home 目录的进程都能拿到 key。共享机器 / 不信任环境请用环境变量,不要用 `login`。
58
58
 
59
- > 把 API Key 当密码对待:不提交进仓库、不贴进聊天。脚本化登录用 `exomind login --api-key ...`(注意别让 key 进 shell 历史或进程列表);交互式 `exomind login` 的 prompt 读取不走 shell 历史。
59
+ > 把 API Key 当密码对待:不提交进仓库、不贴进聊天。脚本化登录用 `emcli login --api-key ...`(注意别让 key 进 shell 历史或进程列表);交互式 `emcli login` 的 prompt 读取不走 shell 历史。
60
60
 
61
61
  ## 接入 Claude Code / Codex(一条命令,默认全装)
62
62
 
63
63
  ```bash
64
- exomind install # 装 skill(Claude+Codex)+ hook(Claude)+ MCP(各宿主),全部自动(幂等+备份)
65
- # 只装某个宿主: exomind install --host codex (claude | codex | opencode)
64
+ emcli install # 装 skill(Claude+Codex)+ hook(Claude)+ MCP(各宿主),全部自动(幂等+备份)
65
+ # 只装某个宿主: emcli install --host codex (claude | codex | opencode)
66
66
  # 跳过某项: --no-skill / --no-hook / --no-mcp
67
67
  ```
68
68
 
69
- **Codex**(skill + MCP,无 hook):装到 `$CODEX_HOME/skills/exomind/`(缺省 `~/.codex/`),MCP 写入 `$CODEX_HOME/config.toml`。**Codex 没有 Claude 的 UserPromptSubmit hook**,靠 skill 的触发词(jdit/存档/查询)驱动;MCP `ingest` 只收文本,目录导入走 `exomind ingest --dir`。装完**重启 Codex**,skill 列表应出现 `exomind`。
69
+ **Codex**(skill + MCP,无 hook):装到 `$CODEX_HOME/skills/exomind/`(缺省 `~/.codex/`),MCP 写入 `$CODEX_HOME/config.toml`。**Codex 没有 Claude 的 UserPromptSubmit hook**,靠 skill 的触发词(jdit/存档/查询)驱动;MCP `ingest` 只收文本,目录导入走 `emcli ingest --dir`。装完**重启 Codex**,skill 列表应出现 `exomind`。
70
70
 
71
- 排查各宿主装没装上:`exomind doctor`(或 `exomind --json doctor`)。
71
+ 排查各宿主装没装上:`emcli doctor`(或 `emcli --json doctor`)。
72
72
 
73
73
  一行完成三层,免手改任何 JSON:
74
74
  - **① MCP 工具**(能力):写 `~/.claude.json` 的 `mcpServers.exomind` → Agent 拿到 `mcp__exomind__*` 确定性工具。
75
75
  - **② skill**(指导):拷到 `~/.claude/skills/exomind/`。
76
- - **③ hook**(闸门):写 `settings.json` 的 `UserPromptSubmit → exomind hook`。
76
+ - **③ hook**(闸门):写 `settings.json` 的 `UserPromptSubmit → emcli hook`。
77
77
 
78
78
  重启 Claude Code 后:
79
79
  - 说 **`存档`** / **`jdit`** → 自动回顾会话、摄入。
@@ -82,18 +82,18 @@ exomind install # 装 skill(Claude+Codex)+ hook(Claude)+ MCP(各宿主)
82
82
 
83
83
  完整接入步骤见服务端仓库 `myExoMindManager/docs/new-machine-setup.md`。
84
84
 
85
- **升级**:`npm i -g exomind@latest && exomind install`(幂等,刷新 skill/hook/mcp;`~/.exomind/` 的 config 与 manifest 保留)。注意:`npm i -g` 只换二进制(CLI+MCP 自动用新),**skill 是拷贝的,需 `exomind install` 才刷新**。
85
+ **升级**:`npm i -g exomind@latest && emcli install`(幂等,刷新 skill/hook/mcp;`~/.exomind/` 的 config 与 manifest 保留)。注意:`npm i -g` 只换二进制(CLI+MCP 自动用新),**skill 是拷贝的,需 `emcli install` 才刷新**。
86
86
 
87
87
  ## 关于 MCP 工具层(Claude Code / OpenCode / Codex 都已默认装)
88
88
 
89
- `exomind install` 一次写**三个宿主**的 MCP 配置(都幂等+备份,互不干扰,各读各的):
89
+ `emcli install` 一次写**三个宿主**的 MCP 配置(都幂等+备份,互不干扰,各读各的):
90
90
  - **Claude Code**:`~/.claude.json` → `mcpServers.exomind`
91
91
  - **OpenCode**:`~/.config/opencode/opencode.json` → `mcp.exomind`
92
92
  - **Codex**:`$CODEX_HOME/config.toml` → `[mcp_servers.exomind]`
93
93
 
94
- 只关 MCP:`exomind install --no-mcp`(三个宿主都不写)。手写/其它宿主(如 Cursor)参考 [docs/mcp.md](./docs/mcp.md)。
94
+ 只关 MCP:`emcli install --no-mcp`(三个宿主都不写)。手写/其它宿主(如 Cursor)参考 [docs/mcp.md](./docs/mcp.md)。
95
95
 
96
- `exomind mcp` 是本地 stdio MCP server,把 ingest/query/search/entity/relations/stats 暴露为 typed tool;复用同一份凭证,三平台都能跑(本地 stdio,不涉及远程 SSE 的 Windows 坑)。
96
+ `emcli mcp` 是本地 stdio MCP server,把 ingest/query/search/entity/relations/stats 暴露为 typed tool;复用同一份凭证,三平台都能跑(本地 stdio,不涉及远程 SSE 的 Windows 坑)。
97
97
 
98
98
  ## 命令一览
99
99
 
@@ -119,11 +119,11 @@ exomind install # 装 skill(Claude+Codex)+ hook(Claude)+ MCP(各宿主)
119
119
  ```
120
120
  Claude Code skill「exomind」(教 Agent 用 CLI)
121
121
  │
122
- UserPromptSubmit hook → exomind hook (跨平台,无 bash/python)
123
- - 存档/jdit 暗号、经验/调研自动检测 → 提示 exomind ingest
122
+ UserPromptSubmit hook → emcli hook (跨平台,无 bash/python)
123
+ - 存档/jdit 暗号、经验/调研自动检测 → 提示 emcli ingest
124
124
  - /keywords + /entities 本地缓存 → 上下文注入(弱服务器友好)
125
125
  │
126
- exomind CLI ──HTTPS REST (Bearer)──▶ ExoMind 服务器
126
+ emcli CLI ──HTTPS REST (Bearer)──▶ ExoMind 服务器
127
127
  /ingest /query /search /entities …
128
128
  ```
129
129
 
@@ -175,7 +175,7 @@ git push --follow-tags # 推 tag → 触发 CI → npm publish(带 provenanc
175
175
  ## 设计要点
176
176
 
177
177
  - **CJS 输出**:tsup `format: cjs`,规避 ESM 打包 CJS 依赖时的 `Dynamic require of "events"`;bin 顶部带 shebang。
178
- - **凭证类型无关**:`exomind login` 存入的字符串以 `Bearer` 发送,服务器 `auth_middleware` 同时接受 API Key 与 GitHub token(`gh_`)。
178
+ - **凭证类型无关**:`emcli login` 存入的字符串以 `Bearer` 发送,服务器 `auth_middleware` 同时接受 API Key 与 GitHub token(`gh_`)。
179
179
  - **hook 弱服务器友好**:`/keywords` 本地缓存 1h,实体描述按 miss 拉取并缓存,per-prompt 命中缓存即零服务器命中。
180
180
 
181
181
  ## License
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.17.0",
3122
+ version: "0.17.2",
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",
@@ -4008,11 +4008,10 @@ function recordFile(manifest, absPath, rawContent, title) {
4008
4008
  size: rawContent.length
4009
4009
  };
4010
4010
  }
4011
- function cleanupStale(m, dir, currentFiles) {
4011
+ function cleanupStale(m, dir) {
4012
4012
  const prefix = path4.resolve(dir) + path4.sep;
4013
- const current = new Set(currentFiles);
4014
4013
  for (const key of Object.keys(m)) {
4015
- if (key.startsWith(prefix) && !current.has(key)) {
4014
+ if (key.startsWith(prefix) && !fs5.existsSync(key)) {
4016
4015
  delete m[key];
4017
4016
  }
4018
4017
  }
@@ -4276,7 +4275,7 @@ async function runDirIngestest(client, opts, dir) {
4276
4275
  await sleep(2e3);
4277
4276
  }
4278
4277
  }
4279
- cleanupStale(manifest, dir, files);
4278
+ cleanupStale(manifest, dir);
4280
4279
  saveManifest(manifest);
4281
4280
  } finally {
4282
4281
  process.removeListener("SIGINT", onSigInt);
@@ -5120,15 +5119,15 @@ async function install(client, opts) {
5120
5119
  const hooks = settings.hooks ?? {};
5121
5120
  const list2 = Array.isArray(hooks.UserPromptSubmit) ? hooks.UserPromptSubmit : [];
5122
5121
  const kept = list2.filter(
5123
- (m) => !(m.hooks || []).some((h) => String(h.command || "").includes("exomind"))
5122
+ (m) => !(m.hooks || []).some((h) => /(?:exomind|emcli) hook/.test(String(h.command || "")))
5124
5123
  );
5125
5124
  kept.push({
5126
- hooks: [{ type: "command", command: "exomind hook", statusMessage: "ExoMind \u77E5\u8BC6\u98DE\u8F6E\u68C0\u7D22" }]
5125
+ hooks: [{ type: "command", command: "emcli hook", statusMessage: "ExoMind \u77E5\u8BC6\u98DE\u8F6E\u68C0\u7D22" }]
5127
5126
  });
5128
5127
  hooks.UserPromptSubmit = kept;
5129
5128
  settings.hooks = hooks;
5130
5129
  fs7.writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + "\n");
5131
- console.log(ok("\u5DF2\u914D\u7F6E UserPromptSubmit hook \u2192 exomind hook (Claude Code \u72EC\u6709)"));
5130
+ console.log(ok("\u5DF2\u914D\u7F6E UserPromptSubmit hook \u2192 emcli hook (Claude Code \u72EC\u6709)"));
5132
5131
  console.log(dim(" Codex \u5F53\u524D\u65E0\u5BF9\u5E94 prompt-submit hook,\u9760 skill \u89E6\u53D1(jdit/\u5B58\u6863/\u67E5\u8BE2)\u3002"));
5133
5132
  }
5134
5133
  if (opts.mcp !== false) {
@@ -5275,7 +5274,7 @@ async function doctor(client) {
5275
5274
  checks.push({
5276
5275
  host: "claude",
5277
5276
  skill: fileExists(claudeSkill) ? "ok" : "missing",
5278
- hook: /exomind/.test(readText(claudeSettings)) ? "ok" : "missing",
5277
+ hook: /(?:exomind|emcli) hook/.test(readText(claudeSettings)) ? "ok" : "missing",
5279
5278
  mcpConfig: mcpServersExomind(claudeJson, "mcpServers") ? "ok" : "missing",
5280
5279
  paths: [claudeSkill, claudeSettings, claudeJson]
5281
5280
  });
@@ -5331,7 +5330,7 @@ async function doctor(client) {
5331
5330
  ` auth: ${authed ? ok("\u2713 \u5DF2\u767B\u5F55") : yellow("\u2717 \u672A\u767B\u5F55/\u5F02\u5E38")}${authErr ? dim(" " + authErr) : ""}`
5332
5331
  );
5333
5332
  console.log(` mcp init: ${mcpInit.ok ? ok("\u2713 " + mcpInit.detail) : yellow("\u2717 " + mcpInit.detail)}`);
5334
- console.log(dim("\n \u7F3A\u9879\u7528 `exomind install [--host <claude|codex|opencode>]` \u8865\u9F50;\u6539\u5B8C\u91CD\u542F\u5BF9\u5E94 Agent\u3002"));
5333
+ console.log(dim("\n \u7F3A\u9879\u7528 `emcli install [--host <claude|codex|opencode>]` \u8865\u9F50;\u6539\u5B8C\u91CD\u542F\u5BF9\u5E94 Agent\u3002"));
5335
5334
  }
5336
5335
 
5337
5336
  // src/cli.ts