open-memex 0.5.0-alpha.5 → 0.5.1
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/AGENTS.md +4 -4
- package/CONTRIBUTING.md +8 -5
- package/README.md +31 -3
- package/README.zh-CN.md +21 -3
- package/dist/cli.js +10 -9
- package/dist/doctor.js +140 -2
- package/docs/SCOPES.md +7 -6
- package/docs/TEST-PLAN.md +10 -3
- package/docs/USER-GUIDE.md +4 -5
- package/docs/USER-GUIDE.zh-CN.md +3 -4
- package/docs/V2-DESIGN.md +9 -1
- package/package.json +1 -1
- package/src/cli.ts +10 -9
- package/src/doctor.ts +139 -2
package/AGENTS.md
CHANGED
|
@@ -12,7 +12,7 @@ via `prepublishOnly` — Node refuses `--experimental-strip-types` for files und
|
|
|
12
12
|
|
|
13
13
|
- **opencode host** loads `src/index.ts` under embedded **Bun**. SQLite here is `bun:sqlite` (built-in).
|
|
14
14
|
- **CLI** (`src/cli.ts`) and smoke tests run under **Node 22+** with `--experimental-strip-types`. SQLite here is `better-sqlite3` (native module).
|
|
15
|
-
- **MCP server** (`src/mcp.ts`, stdio) runs under **Node 22+** with `--experimental-strip-types`. It exposes the same
|
|
15
|
+
- **MCP server** (`src/mcp.ts`, stdio) runs under **Node 22+** with `--experimental-strip-types`. It exposes the same eleven memory tools to any MCP client (VS Code Copilot, Cursor, Claude Code). **stdout is the protocol channel — never log to stdout in `mcp.ts`; diagnostics go to stderr.**
|
|
16
16
|
|
|
17
17
|
`src/store/db.ts` picks the backend at runtime by sniffing `globalThis.Bun`. Both backends share the same surface (`new Database(path)`, `.exec`, `.prepare().run/all/get`, `.close`). Any DB code you write must stay on that common subset — do not import `better-sqlite3` or `bun:sqlite` directly outside `db.ts`.
|
|
18
18
|
|
|
@@ -61,7 +61,7 @@ resolves the server command
|
|
|
61
61
|
at init time — npx fallback when no durable bin is on PATH, D17),
|
|
62
62
|
`open-memex config` prints the effective config, `open-memex capture --dry-run "text"`
|
|
63
63
|
previews keyword capture without writing, `open-memex doctor` runs health checks
|
|
64
|
-
(node version, config, scope resolution, storage writability, MCP handshake).
|
|
64
|
+
(node version, config, scope resolution, storage writability, VS Code MCP enablement, MCP handshake).
|
|
65
65
|
`open-memex init` with no --client auto-detects and wires every installed editor
|
|
66
66
|
(`--yes` skips, scripts never prompt); `open-memex config set <key> <value>` edits settings after install.
|
|
67
67
|
`open-memex uninstall [--client vscode|cursor|opencode|visualstudio] [--global] [--yes]`
|
|
@@ -125,7 +125,7 @@ Context injection happens exactly once per session in `experimental.chat.system.
|
|
|
125
125
|
|
|
126
126
|
`docs/V2-DESIGN.md` is the frozen protocol v0.2 (zero open questions). Per its §12:
|
|
127
127
|
AGENTS.md answers "how should AI work here"; the design doc answers "why is it
|
|
128
|
-
built this way" (principles, iron rules, D1–
|
|
128
|
+
built this way" (principles, iron rules, D1–D49 decision log). Before changing
|
|
129
129
|
architecture, scope semantics, lifecycle, or the protocol surface (frontmatter
|
|
130
130
|
schema, MCP tools, CLI contract), read the relevant design section — the decision
|
|
131
131
|
log records what was already considered and rejected.
|
|
@@ -138,7 +138,7 @@ build roadmap; the design doc tracks the *why*.
|
|
|
138
138
|
|
|
139
139
|
## Branch workflow
|
|
140
140
|
|
|
141
|
-
`dev/<topic>` → PR → `main` (
|
|
141
|
+
`dev/<topic>` → PR → `main` (alpha versions published with
|
|
142
142
|
`npm publish --tag alpha`, npm `latest` moves only on stable releases).
|
|
143
143
|
The `V2` integration branch was retired 2026-09-29 — its job (isolating the
|
|
144
144
|
breaking v1→v2 transition) shipped with 0.3.0. Full rules: `CONTRIBUTING.md`.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## Branch workflow
|
|
4
4
|
|
|
5
|
-
- `main` — the
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
- `main` — the only line (the `V2` integration branch was retired 2026-09-29).
|
|
6
|
+
Land work via pull request from a `dev/<topic>` branch. Exception: tiny
|
|
7
|
+
text-only doc tweaks may go directly to `main`, but only after the owner
|
|
8
|
+
has previewed and approved the exact change. Alpha versions
|
|
9
|
+
(e.g. `0.5.0-alpha.x`) live on `main`; publish them with
|
|
10
|
+
`npm publish --tag alpha` so the npm `latest` tag only moves on stable
|
|
11
|
+
releases.
|
|
9
12
|
- `dev/<topic>` — feature/fix branches (e.g. `dev/init-ux`). Open as **draft**
|
|
10
13
|
PRs against `main`; mark ready and merge after local testing passes.
|
|
11
14
|
|
|
@@ -25,7 +28,7 @@ branches are cheap.)
|
|
|
25
28
|
## Design authority
|
|
26
29
|
|
|
27
30
|
Protocol decisions live in `docs/V2-DESIGN.md` (frozen v0.2, decision log
|
|
28
|
-
D1–
|
|
31
|
+
D1–D49). Changing architecture, scope semantics, lifecycle, or the protocol
|
|
29
32
|
surface (frontmatter schema, MCP tools, CLI contract) requires updating the
|
|
30
33
|
design doc first. `AGENTS.md` has the working notes for AI agents; this file
|
|
31
34
|
has the contributor workflow.
|
package/README.md
CHANGED
|
@@ -23,6 +23,20 @@ automatically.
|
|
|
23
23
|
|
|
24
24
|
> No capture, nothing to inherit.
|
|
25
25
|
|
|
26
|
+
### One memory, every agent
|
|
27
|
+
|
|
28
|
+
Most developers don't use one AI tool — they use several on the same machine:
|
|
29
|
+
Copilot in VS Code, Cursor, opencode, Claude Code. Each tool keeps
|
|
30
|
+
its own silo: a decision made in one is invisible to the others.
|
|
31
|
+
|
|
32
|
+
open-memex is tool-agnostic by design. Memory lives as Markdown + SQLite next
|
|
33
|
+
to your project, and every editor talks to it through the same MCP interface.
|
|
34
|
+
Wire up two, three, five clients with `open-memex init` — they all read and
|
|
35
|
+
write the same memory on that machine. A constraint captured in VS Code is respected in
|
|
36
|
+
opencode; a lesson learned in Cursor shows up in Claude Code.
|
|
37
|
+
|
|
38
|
+
> Your memory belongs to you — not to your tools.
|
|
39
|
+
|
|
26
40
|
It also complements agentic development workflows (spec-driven development,
|
|
27
41
|
plan/implement/verify loops): plans produce decisions, verification produces
|
|
28
42
|
rules — open-memex is the memory layer that keeps them across sessions instead
|
|
@@ -36,6 +50,7 @@ of re-deriving them on every run.
|
|
|
36
50
|
| Review before sharing | Yes — outbox + PR | Varies | Yes | No |
|
|
37
51
|
| Agent recall | Session-start injection + search | API calls | Manual lookup | No |
|
|
38
52
|
| Human-readable | Plain Markdown files | Dashboard / API | Yes | No |
|
|
53
|
+
| Works across AI tools | Yes — any MCP client (same machine) | Per-integration | No | No |
|
|
39
54
|
|
|
40
55
|
- **Markdown files** as the source of truth (human-editable, git-friendly)
|
|
41
56
|
- **SQLite FTS5** as a rebuildable index (BM25 keyword search, via `better-sqlite3`)
|
|
@@ -90,7 +105,7 @@ personal scope: this machine only — never synced, never enters a repo.
|
|
|
90
105
|
npm install -g open-memex
|
|
91
106
|
```
|
|
92
107
|
|
|
93
|
-
This installs the `0.
|
|
108
|
+
This installs the `0.5.1` stable release.
|
|
94
109
|
|
|
95
110
|
**Alpha** (bleeding edge, for testers) — the `alpha` tag:
|
|
96
111
|
|
|
@@ -219,7 +234,8 @@ open-memex init --client opencode --global --yes
|
|
|
219
234
|
```
|
|
220
235
|
|
|
221
236
|
Merges `"plugin": ["file:///absolute/path/to/open-memex/src/index.ts"]` into your
|
|
222
|
-
user-level `~/.config/opencode/opencode.json`
|
|
237
|
+
user-level `~/.config/opencode/opencode.json` (or `opencode.jsonc` if that is
|
|
238
|
+
the file you already have) — one-time, every project picks it
|
|
223
239
|
up, no per-project init. You get keyword auto-capture and first-turn context
|
|
224
240
|
injection on top of the tools. (A config file with comments is left untouched —
|
|
225
241
|
add the `plugin` line by hand in that case.)
|
|
@@ -623,6 +639,18 @@ distill-to-AGENTS.md assist (`distill-agents`, propose-only — you merge by han
|
|
|
623
639
|
§3.5 checkpoint distillation in the MCP handshake + init instructions (the agent
|
|
624
640
|
proposes 1–3 captures at checkpoints, the human decides); 1–2 colleague pilot.
|
|
625
641
|
|
|
642
|
+
**`0.5.0` (stable):** init UX pass — `init --global` writes the editor wiring
|
|
643
|
+
once at user level (D45); bare `init` auto-detects installed editors and wires
|
|
644
|
+
them all (D46); non-JSON configs are left untouched with a paste-ready snippet
|
|
645
|
+
instead of an error (D47); `uninstall` reverses `init` without touching memory
|
|
646
|
+
data (D48); empty config files are treated as blank, not corrupt (D49).
|
|
647
|
+
"One memory, every agent": every editor on the same machine reads and writes
|
|
648
|
+
the same memory through one MCP interface.
|
|
649
|
+
|
|
650
|
+
**`0.5.1` (stable):** `--help` accuracy fixes — the `mcp` help text now states the
|
|
651
|
+
server exposes 11 tools (a superset of the opencode plugin's five memory tools),
|
|
652
|
+
and install hints point at the stable line instead of `@alpha` (F27).
|
|
653
|
+
|
|
626
654
|
**Future (signal-gated, no version committed):** org layer — org memory repo,
|
|
627
655
|
curator convention; native agent plugins (Claude Code / Codex hooks as
|
|
628
656
|
enhancement paths over the same MCP tools); local embeddings as a
|
|
@@ -669,7 +697,7 @@ project. A per-project `.vscode/mcp.json` still wins when present, and the
|
|
|
669
697
|
entry keeps `cwd=${workspaceFolder}` so project-scope resolution keeps
|
|
670
698
|
working per window. If your user-level `mcp.json` has comments (VS Code
|
|
671
699
|
accepts JSONC), `init` leaves it alone and prints the exact snippet to add
|
|
672
|
-
by hand.
|
|
700
|
+
by hand. An empty file is treated as blank and written to directly.
|
|
673
701
|
|
|
674
702
|
**How do I remove the editor wiring?**
|
|
675
703
|
`open-memex uninstall` reverses `init`: it removes the MCP server entry,
|
package/README.zh-CN.md
CHANGED
|
@@ -21,6 +21,18 @@ open-memex 把值得记住的部分——决策、约束、教训——存成可
|
|
|
21
21
|
|
|
22
22
|
> No capture, nothing to inherit.(不记录,就无从传承。)
|
|
23
23
|
|
|
24
|
+
### 一份记忆,所有 Agent 通用
|
|
25
|
+
|
|
26
|
+
大多数开发者并不是只用一个 AI 工具——同一台电脑上可能装着 VS Code Copilot、
|
|
27
|
+
Cursor、opencode、Claude Code。但每个工具的记忆都是孤岛:在 A 里定好的决策,B 一无所知。
|
|
28
|
+
|
|
29
|
+
open-memex 天生与工具无关。记忆以 Markdown + SQLite 的形式存在项目旁边,
|
|
30
|
+
所有编辑器都通过同一个 MCP 接口读写。用 `open-memex init` 接上两三个客户端,
|
|
31
|
+
它们读写的是这台机器上的同一份记忆:在 VS Code 里记下的约束,opencode 会遵守;
|
|
32
|
+
在 Cursor 里学到的教训,Claude Code 也看得到。
|
|
33
|
+
|
|
34
|
+
> 记忆属于你,不属于工具。
|
|
35
|
+
|
|
24
36
|
它也补齐了 agentic 开发工作流(spec 驱动开发、plan/implement/verify 循环)缺的那一块:
|
|
25
37
|
plan 产出决策,verify 产出规则——open-memex 是让它们跨会话留存的记忆层,
|
|
26
38
|
而不是每次从头重新推导。
|
|
@@ -33,6 +45,7 @@ plan 产出决策,verify 产出规则——open-memex 是让它们跨会话留
|
|
|
33
45
|
| 分享前 review | 有——outbox + PR | 不一定 | 有 | 没有 |
|
|
34
46
|
| Agent 回忆 | 会话开始注入 + 搜索 | 调 API | 人工去查 | 没有 |
|
|
35
47
|
| 人类可读 | 纯 Markdown 文件 | 后台 / API | 有 | 没有 |
|
|
48
|
+
| 跨 AI 工具通用 | 可以——同一台机器上的任何 MCP 客户端 | 按集成逐个对接 | 不可以 | 不可以 |
|
|
36
49
|
|
|
37
50
|
- **Markdown 文件**是 source of truth(人类可读、git 友好)
|
|
38
51
|
- **SQLite FTS5** 做可重建索引(BM25 关键词检索,`better-sqlite3`)
|
|
@@ -87,7 +100,7 @@ personal scope:只属于这台机器——永不同步,永远进不了仓库
|
|
|
87
100
|
npm install -g open-memex
|
|
88
101
|
```
|
|
89
102
|
|
|
90
|
-
安装的是 `0.
|
|
103
|
+
安装的是 `0.5.1` 正式版。
|
|
91
104
|
|
|
92
105
|
**Alpha 版**(最新开发版,给测试者)——`alpha` 标签:
|
|
93
106
|
|
|
@@ -213,7 +226,8 @@ open-memex init --client opencode --global --yes
|
|
|
213
226
|
```
|
|
214
227
|
|
|
215
228
|
把 `"plugin": ["file:///absolute/path/to/open-memex/src/index.ts"]` 合并进用户级
|
|
216
|
-
`~/.config/opencode/opencode.json
|
|
229
|
+
`~/.config/opencode/opencode.json`(如果你用的是 `opencode.jsonc`,就合并进那个)
|
|
230
|
+
——一次配置,每个项目自动生效,不用逐个项目
|
|
217
231
|
init。在 tools 之外还能获得关键词自动捕获和首轮上下文注入。(带注释的配置文件
|
|
218
232
|
不会被改动——那种情况请手动加 `plugin` 这一行。)
|
|
219
233
|
|
|
@@ -587,6 +601,10 @@ distill-to-AGENTS.md 辅助(`distill-agents`,只提议不改写——人工
|
|
|
587
601
|
§3.5 检查点蒸馏写进 MCP 握手指令和 init 指令文件
|
|
588
602
|
(agent 在检查点提议 1–3 条捕获,人来定);找 1–2 个同事做 pilot。
|
|
589
603
|
|
|
604
|
+
**`0.5.0`(稳定版):** init 体验整修——`init --global` 一次写好用户级编辑器接线(D45);裸 `init` 自动检测已装编辑器并一次全接上(D46);非标准 JSON 配置不再报错,而是原样保留并打印手贴片段(D47);`uninstall` 逆转 `init` 且永不碰记忆数据(D48);空配置文件按空白处理、不再误判为损坏(D49)。"一份记忆,所有 Agent 通用":同一台机器上的每个编辑器,经由同一个 MCP 接口读写同一份记忆。
|
|
605
|
+
|
|
606
|
+
**`0.5.1`(稳定版):** `--help` 文案准确性修正——`mcp` 帮助写明 server 暴露 11 个工具(含 opencode 插件的 5 个 memory 工具),安装提示改指稳定版而非 `@alpha`(F27)。
|
|
607
|
+
|
|
590
608
|
**未来(看信号再定,不承诺版本):** 组织层——组织记忆仓库、curator 约定;
|
|
591
609
|
原生 agent 插件(Claude Code / Codex hooks,作为同一套 MCP tools 的增强路径);
|
|
592
610
|
本地 embedding 做基准测试门控的实验(**未经明确 opt-in 绝不下载
|
|
@@ -625,7 +643,7 @@ Linux:`~/.config/Code/User/mcp.json`),每个项目打开 server 都在。
|
|
|
625
643
|
项目里如果有 `.vscode/mcp.json` 仍然优先;entry 里保留了
|
|
626
644
|
`cwd=${workspaceFolder}`,project scope 按窗口照常工作。
|
|
627
645
|
如果你的用户级 `mcp.json` 带注释(VS Code 接受 JSONC),`init` 不会碰它,
|
|
628
|
-
|
|
646
|
+
只打印可直接手贴的配置片段。空文件会被当作空白直接写入。
|
|
629
647
|
|
|
630
648
|
**怎么拆掉编辑器接线?**
|
|
631
649
|
`open-memex uninstall` 就是 `init` 的逆操作:删掉 MCP server 条目、opencode
|
package/dist/cli.js
CHANGED
|
@@ -296,8 +296,9 @@ Usage: open-memex capture --dry-run "text"
|
|
|
296
296
|
Example:
|
|
297
297
|
open-memex capture --dry-run "remember: we deploy on Fridays"`,
|
|
298
298
|
doctor: `Environment health check: Node version, config source, scope resolution,
|
|
299
|
-
storage writability,
|
|
300
|
-
|
|
299
|
+
storage writability, VS Code MCP enablement (settings.json + system policy),
|
|
300
|
+
then boots a real MCP server and runs initialize + tools/list against it —
|
|
301
|
+
all eleven tools must show up.
|
|
301
302
|
|
|
302
303
|
Usage: open-memex doctor
|
|
303
304
|
|
|
@@ -343,7 +344,7 @@ Usage:
|
|
|
343
344
|
Every command has its own help with description and examples:
|
|
344
345
|
open-memex <command> --help (or -h)
|
|
345
346
|
|
|
346
|
-
One-command project setup: \`open-memex init\` (or \`npx open-memex
|
|
347
|
+
One-command project setup: \`open-memex init\` (or \`npx -y open-memex init\`) detects
|
|
347
348
|
your installed editors and wires them all — user-level where the editor supports it
|
|
348
349
|
(VS Code / Cursor MCP config, opencode native plugin), so one init covers every project;
|
|
349
350
|
Visual Studio is included when the project has a solution file (its \`.mcp.json\`
|
|
@@ -358,9 +359,9 @@ confirms the detected editors and asks a couple of settings (keyword capture,
|
|
|
358
359
|
first-turn injection); \`--yes\` accepts all defaults, and non-terminal runs never prompt.
|
|
359
360
|
\`open-memex config set <key> <value>\` changes those settings after install.
|
|
360
361
|
|
|
361
|
-
Once installed globally (\`npm i -g open-memex
|
|
362
|
-
available directly: \`open-memex mcp\` starts the stdio MCP server (
|
|
363
|
-
|
|
362
|
+
Once installed globally (\`npm i -g open-memex\`) the \`open-memex\` command is
|
|
363
|
+
available directly: \`open-memex mcp\` starts the stdio MCP server (11 tools, a superset of
|
|
364
|
+
the opencode plugin's five memory_* tools); \`open-memex mcp --print-config <client>\`
|
|
364
365
|
prints a copy-paste MCP client config snippet.
|
|
365
366
|
|
|
366
367
|
Scope defaults to \`project\` (derived from cwd's git remote or path).
|
|
@@ -433,7 +434,7 @@ function resolveCliScope(flags, project) {
|
|
|
433
434
|
: project;
|
|
434
435
|
}
|
|
435
436
|
/** Print a copy-paste MCP client config snippet. Requires a global install
|
|
436
|
-
* (`npm i -g open-memex
|
|
437
|
+
* (`npm i -g open-memex`) so the `open-memex` command is on PATH. */
|
|
437
438
|
function printMcpConfig(client) {
|
|
438
439
|
const c = client.toLowerCase();
|
|
439
440
|
// D17: resolve the server command the same way `init` does.
|
|
@@ -489,7 +490,7 @@ function printMcpConfig(client) {
|
|
|
489
490
|
process.exit(1);
|
|
490
491
|
}
|
|
491
492
|
if (!mc.durable) {
|
|
492
|
-
console.error(`\n# note: no durable \`open-memex\` on PATH — snippet uses npx. \`npm i -g open-memex
|
|
493
|
+
console.error(`\n# note: no durable \`open-memex\` on PATH — snippet uses npx. \`npm i -g open-memex\` for faster startup.`);
|
|
493
494
|
}
|
|
494
495
|
process.exit(0);
|
|
495
496
|
}
|
|
@@ -648,7 +649,7 @@ async function main() {
|
|
|
648
649
|
}
|
|
649
650
|
return;
|
|
650
651
|
}
|
|
651
|
-
// `mcp` starts the stdio MCP server (
|
|
652
|
+
// `mcp` starts the stdio MCP server (11 tools; the opencode plugin exposes 5).
|
|
652
653
|
// Branched before db() — runMcpServer() does its own init, and stdout must
|
|
653
654
|
// stay clean for the MCP protocol.
|
|
654
655
|
if (cmd === "mcp") {
|
package/dist/doctor.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// Read-only except that paths() and the MCP handshake may create the (empty)
|
|
4
4
|
// data directories, exactly like a normal `open-memex mcp` start would.
|
|
5
5
|
import fs from "node:fs";
|
|
6
|
+
import os from "node:os";
|
|
6
7
|
import path from "node:path";
|
|
7
|
-
import { spawn } from "node:child_process";
|
|
8
|
+
import { spawn, execFileSync } from "node:child_process";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { loadConfig, configSource, DEFAULT_CONFIG } from "./config.js";
|
|
10
11
|
import { paths } from "./paths.js";
|
|
@@ -136,9 +137,146 @@ function mcpCheck() {
|
|
|
136
137
|
});
|
|
137
138
|
});
|
|
138
139
|
}
|
|
140
|
+
/** Parse JSON tolerating line/block comments plus trailing commas
|
|
141
|
+
* (VS Code's settings.json is JSONC). Health-check grade, not a full parser. */
|
|
142
|
+
function parseLenientJson(raw) {
|
|
143
|
+
try {
|
|
144
|
+
return JSON.parse(raw);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* fall through to comment stripping */
|
|
148
|
+
}
|
|
149
|
+
let out = "";
|
|
150
|
+
let i = 0;
|
|
151
|
+
let inStr = false;
|
|
152
|
+
let esc = false;
|
|
153
|
+
while (i < raw.length) {
|
|
154
|
+
const c = raw[i];
|
|
155
|
+
const n = raw[i + 1];
|
|
156
|
+
if (inStr) {
|
|
157
|
+
out += c;
|
|
158
|
+
if (esc)
|
|
159
|
+
esc = false;
|
|
160
|
+
else if (c === "\\")
|
|
161
|
+
esc = true;
|
|
162
|
+
else if (c === '"')
|
|
163
|
+
inStr = false;
|
|
164
|
+
i++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (c === '"') {
|
|
168
|
+
inStr = true;
|
|
169
|
+
out += c;
|
|
170
|
+
i++;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (c === "/" && n === "/") {
|
|
174
|
+
while (i < raw.length && raw[i] !== "\n")
|
|
175
|
+
i++;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (c === "/" && n === "*") {
|
|
179
|
+
i += 2;
|
|
180
|
+
while (i < raw.length && !(raw[i] === "*" && raw[i + 1] === "/"))
|
|
181
|
+
i++;
|
|
182
|
+
i += 2;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
out += c;
|
|
186
|
+
i++;
|
|
187
|
+
}
|
|
188
|
+
out = out.replace(/,\s*([}\]])/g, "$1");
|
|
189
|
+
return JSON.parse(out);
|
|
190
|
+
}
|
|
191
|
+
function vscodeSettingsPath() {
|
|
192
|
+
const home = os.homedir();
|
|
193
|
+
if (process.platform === "win32") {
|
|
194
|
+
const appdata = process.env.APPDATA;
|
|
195
|
+
return appdata ? path.join(appdata, "Code", "User", "settings.json") : null;
|
|
196
|
+
}
|
|
197
|
+
if (process.platform === "darwin") {
|
|
198
|
+
return path.join(home, "Library", "Application Support", "Code", "User", "settings.json");
|
|
199
|
+
}
|
|
200
|
+
return path.join(home, ".config", "Code", "User", "settings.json");
|
|
201
|
+
}
|
|
202
|
+
/** True when a Windows system policy disables MCP (value name contains "mcp",
|
|
203
|
+
* data is 0/0x0/false). Checks HKLM and HKCU policy keys. */
|
|
204
|
+
function windowsMcpPolicyDisabled() {
|
|
205
|
+
if (process.platform !== "win32")
|
|
206
|
+
return null;
|
|
207
|
+
for (const hive of ["HKLM", "HKCU"]) {
|
|
208
|
+
try {
|
|
209
|
+
const stdout = execFileSync("reg", ["query", `${hive}\\SOFTWARE\\Policies\\Microsoft\\VSCode`], { encoding: "utf8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] });
|
|
210
|
+
for (const line of stdout.split("\n")) {
|
|
211
|
+
const m = line.match(/^\s{2,}(\S+)\s+REG_\w+\s+(\S+)/);
|
|
212
|
+
if (m && /mcp/i.test(m[1]) && /^(0x0|0|false)$/i.test(m[2])) {
|
|
213
|
+
return `${hive}\\SOFTWARE\\Policies\\Microsoft\\VSCode!${m[1]}`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
/* policy key absent — no policy */
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
function settingsMcpDisabled(file) {
|
|
224
|
+
try {
|
|
225
|
+
const parsed = parseLenientJson(fs.readFileSync(file, "utf8"));
|
|
226
|
+
return parsed["chat.mcp.enabled"] === false;
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
return false; // unreadable file: don't claim anything
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** VS Code ignores MCP server entries entirely when MCP is switched off —
|
|
233
|
+
* either in settings.json or, on managed machines, by system policy. */
|
|
234
|
+
function vscodeMcpCheck() {
|
|
235
|
+
const name = "vscode-mcp";
|
|
236
|
+
const policyHit = windowsMcpPolicyDisabled();
|
|
237
|
+
if (policyHit) {
|
|
238
|
+
return {
|
|
239
|
+
name,
|
|
240
|
+
ok: false,
|
|
241
|
+
detail: `MCP is disabled by system policy (${policyHit}) — managed by your organization. ` +
|
|
242
|
+
`VS Code will ignore open-memex's MCP entry on this machine.`,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const files = [];
|
|
246
|
+
const user = vscodeSettingsPath();
|
|
247
|
+
if (user)
|
|
248
|
+
files.push(user);
|
|
249
|
+
const ws = path.join(process.cwd(), ".vscode", "settings.json");
|
|
250
|
+
if (!files.includes(ws))
|
|
251
|
+
files.push(ws);
|
|
252
|
+
const found = [];
|
|
253
|
+
const disabled = [];
|
|
254
|
+
for (const f of files) {
|
|
255
|
+
if (!fs.existsSync(f))
|
|
256
|
+
continue;
|
|
257
|
+
found.push(f);
|
|
258
|
+
if (settingsMcpDisabled(f))
|
|
259
|
+
disabled.push(f);
|
|
260
|
+
}
|
|
261
|
+
if (disabled.length > 0) {
|
|
262
|
+
return {
|
|
263
|
+
name,
|
|
264
|
+
ok: false,
|
|
265
|
+
detail: `chat.mcp.enabled is false in ${disabled.join(", ")} — VS Code will not load ` +
|
|
266
|
+
`MCP servers. Set it to true (or ask IT if the setting shows as managed).`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
name,
|
|
271
|
+
ok: true,
|
|
272
|
+
detail: found.length > 0
|
|
273
|
+
? `MCP enabled (checked ${found.join(", ")})`
|
|
274
|
+
: "VS Code settings not found on this machine — nothing to check",
|
|
275
|
+
};
|
|
276
|
+
}
|
|
139
277
|
export async function runDoctor() {
|
|
140
278
|
console.log("open-memex doctor");
|
|
141
|
-
const checks = [nodeCheck(), configCheck(), scopeCheck(), storageCheck()];
|
|
279
|
+
const checks = [nodeCheck(), configCheck(), scopeCheck(), storageCheck(), vscodeMcpCheck()];
|
|
142
280
|
checks.push(await mcpCheck());
|
|
143
281
|
let allOk = true;
|
|
144
282
|
for (const c of checks) {
|
package/docs/SCOPES.md
CHANGED
|
@@ -64,14 +64,15 @@ moves `memories/user/` → `memories/personal/` and rewrites the frontmatter
|
|
|
64
64
|
tree is kept. Reads remain backward compatible: a v1 file with `scope: user`
|
|
65
65
|
is interpreted as `personal`.
|
|
66
66
|
|
|
67
|
-
## Visibility
|
|
67
|
+
## Visibility
|
|
68
68
|
|
|
69
69
|
v2 frontmatter carries a separate `visibility` field (`private` | `internal` |
|
|
70
|
-
`shared`)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
boundary and review anything you
|
|
70
|
+
`shared`), defaulting to `private` for the personal scope and `internal` for
|
|
71
|
+
the project scope. `open-memex export` excludes `visibility: private` memories
|
|
72
|
+
by default (`--all` / `-a` includes them, D40). Physical isolation of private
|
|
73
|
+
memories into a local-only cache directory is still planned; today, treat
|
|
74
|
+
`personal` as the only hard confidentiality boundary and review anything you
|
|
75
|
+
place under `.ai/open-memex/` before pushing.
|
|
75
76
|
|
|
76
77
|
## Reserved names
|
|
77
78
|
|
package/docs/TEST-PLAN.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# OpenMemex 测试计划(v0.
|
|
1
|
+
# OpenMemex 测试计划(v0.5.1)
|
|
2
2
|
|
|
3
3
|
> 自动化部分:`node --experimental-strip-types scripts/test-full.ts`
|
|
4
4
|
> 62 项全过(26 个 CLI 命令 + 11 个 MCP tool),隔离环境运行,不碰真实数据。
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## A. Windows 真机 + VS Code Copilot
|
|
8
8
|
|
|
9
|
-
- [ ] `npm i -g open-memex
|
|
9
|
+
- [ ] `npm i -g open-memex` 全局安装(稳定版),`open-memex --version` 显示正确版本
|
|
10
10
|
- [ ] 在一个真实项目目录跑 `open-memex init`(不加 `--yes`,走一遍交互)
|
|
11
11
|
- 确认 `.vscode/mcp.json` 生成,`~/.copilot/copilot-instructions.md` 合并写入(不覆盖已有内容)
|
|
12
12
|
- [ ] 重启 VS Code,Copilot Chat 里问 "what do you remember about this project?"
|
|
@@ -60,10 +60,17 @@
|
|
|
60
60
|
|
|
61
61
|
## G. 同事 pilot(1–2 人,Stone 私下选)
|
|
62
62
|
|
|
63
|
-
- [ ] 对方 `npx open-memex
|
|
63
|
+
- [ ] 对方 `npx -y open-memex init` 走通
|
|
64
64
|
- [ ] 对方能 propose → 你这边能看到 PR → promote 流程走通
|
|
65
65
|
- [ ] 收集反馈:哪里卡、哪里不符合直觉
|
|
66
66
|
|
|
67
|
+
## I. init/uninstall 行为(D47–D49)
|
|
68
|
+
|
|
69
|
+
- [ ] 空的 `mcp.json`:`open-memex init --client vscode` 直接写入,不再报 "not valid JSON"(D49)
|
|
70
|
+
- [ ] 带注释的 `mcp.json`:`init` 不动文件,只打印手贴片段(D47)
|
|
71
|
+
- [ ] `open-memex uninstall --client vscode` 移除接线条目,记忆数据不动;再跑 `init` 可恢复(D48)
|
|
72
|
+
- [ ] 裸 `open-memex uninstall`(交互终端)会先确认再清所有编辑器;`--yes` 跳过确认
|
|
73
|
+
|
|
67
74
|
## H. 已知问题观察
|
|
68
75
|
|
|
69
76
|
- [ ] better-sqlite3 在 Node 24 退出时偶发 crash(exit 134):注意是否丢数据(预期:不丢,只影响退出码)
|
package/docs/USER-GUIDE.md
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> This document describes open-memex's **mental model**: where your memories live,
|
|
4
4
|
> how they flow, and who can see them. The in-repo directory (§2, §6 write path)
|
|
5
|
-
> and the propose → promote → resolve workflow (§5)
|
|
6
|
-
>
|
|
7
|
-
> everything else is 0.3.0 behavior.
|
|
5
|
+
> and the propose → promote → resolve workflow (§5) shipped in 0.4.0
|
|
6
|
+
> (Phase 2B); everything described here is current as of 0.5.0.
|
|
8
7
|
|
|
9
8
|
## In one sentence
|
|
10
9
|
|
|
@@ -172,7 +171,7 @@ personal idea ──propose──▶ outbox draft ──submit──▶ proposed
|
|
|
172
171
|
- **Submit** (explicit, your call): `open-memex submit <id...>` → local branch
|
|
173
172
|
+ local commit into `.ai/open-memex/`; push/PR are printed for you (or done
|
|
174
173
|
by your agent on your Yes).
|
|
175
|
-
- **Pull
|
|
174
|
+
- **Pull**: `open-memex pull` (always explicit, never automatic) → git fetch +
|
|
176
175
|
fast-forward → scans `.ai/open-memex/*.md` → merges into the local `index.db` by
|
|
177
176
|
file mtime. Retrieval always goes through SQLite, never walks git.
|
|
178
177
|
- **personal scope**: never syncs (§1 iron rule).
|
|
@@ -194,4 +193,4 @@ personal idea ──propose──▶ outbox draft ──submit──▶ proposed
|
|
|
194
193
|
|
|
195
194
|
---
|
|
196
195
|
|
|
197
|
-
*Companion design record: `docs/V2-DESIGN.md` (decisions D1–
|
|
196
|
+
*Companion design record: `docs/V2-DESIGN.md` (decisions D1–D49).*
|
package/docs/USER-GUIDE.zh-CN.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 本文档讲的是 open-memex 的**心智模型**:你的记忆住在哪里、怎么流动、谁能看到。
|
|
4
4
|
> in-repo 目录(§2、§6 的写路径)和 propose → promote → resolve 工作流(§5)
|
|
5
|
-
>
|
|
6
|
-
> 其余为 0.3.0 已有行为。
|
|
5
|
+
> 已随 0.4.0(Phase 2B)发布;本文描述的均为 0.5.0 现行行为。
|
|
7
6
|
|
|
8
7
|
## 一句话
|
|
9
8
|
|
|
@@ -143,7 +142,7 @@ server 不能主动推送,调不调 `memory_search` 全看 model 的判断。
|
|
|
143
142
|
**不碰 repo、不自动 commit、不自动 push**。
|
|
144
143
|
- **交**(显式,你说了算):`open-memex submit <id...>` → 本地分支 + 本地 commit
|
|
145
144
|
进 `.ai/open-memex/`;push/PR 命令打印给你(或你的 agent 拿着你的 Yes 自己做)。
|
|
146
|
-
-
|
|
145
|
+
- **拉**:`open-memex pull`(必须显式,没有自动)→ git fetch + fast-forward →
|
|
147
146
|
扫描 `.ai/open-memex/*.md` → 按文件 mtime 合进本地 `index.db`。检索永远走 SQLite,不 walk git。
|
|
148
147
|
- **personal scope**:永远不同步(§1 铁律)。
|
|
149
148
|
- **没 git 的项目**:照常用,project scope 降级为纯本地并明确提示,不会坏掉。
|
|
@@ -158,4 +157,4 @@ server 不能主动推送,调不调 `memory_search` 全看 model 的判断。
|
|
|
158
157
|
|
|
159
158
|
---
|
|
160
159
|
|
|
161
|
-
*配套设计文档:`docs/V2-DESIGN.md`(D1–
|
|
160
|
+
*配套设计文档:`docs/V2-DESIGN.md`(D1–D49 决策记录)。*
|
package/docs/V2-DESIGN.md
CHANGED
|
@@ -494,7 +494,7 @@ Zero-config is survival for an open-source project. The opencode plugin remains
|
|
|
494
494
|
- **Phase 1 — Local hardening (1–2 wks).** CJK default (bigram+FTS5) · v1→v2 migration · dedup +
|
|
495
495
|
lifecycle · redaction hardening · scope docs. No external dependencies.
|
|
496
496
|
- **Phase 2A — MCP server (shipped 2026-09-27, D15).** Core/adapters split
|
|
497
|
-
(`src/tools/ops.ts`) · MCP server (`src/mcp.ts`, stdio) exposing all
|
|
497
|
+
(`src/tools/ops.ts`) · MCP server (`src/mcp.ts`, stdio) exposing all eleven memory tools —
|
|
498
498
|
read-only-first phasing dropped per D15 · query-aware injection stays host-side.
|
|
499
499
|
Ships in **`0.3.0-alpha`** (with bin/npx user-friendliness polish per §17 adoption path).
|
|
500
500
|
- **Phase 2B — Team sync.** GitProvider · `propose/promote/resolve` · in-repo dir · 1–2 colleague pilot
|
|
@@ -538,6 +538,14 @@ requirement: personal data never touches third-party services). Benchmarks to tr
|
|
|
538
538
|
curator convention ✅ `docs/CURATOR.md` (2026-09-29, pulled forward) ·
|
|
539
539
|
distill-to-AGENTS.md assist ✅ `open-memex distill-agents` (2026-09-29, pulled forward) ·
|
|
540
540
|
export/import archive command ✅ `open-memex export` / `import` (2026-09-29, pulled forward, D40).
|
|
541
|
+
- **0.5.0 (stable, 2026-09-29).** Init UX pass: `init --global` user-level editor
|
|
542
|
+
wiring (D45) · bare-init auto-detect wires all installed editors (D46) · JSONC
|
|
543
|
+
configs left untouched with a paste-ready snippet (D47) · `uninstall` reverses
|
|
544
|
+
`init` without touching memory data (D48) · empty config files treated as
|
|
545
|
+
blank, not corrupt (D49).
|
|
546
|
+
- **0.5.1 (stable).** `--help` accuracy: `mcp` help states the server exposes 11
|
|
547
|
+
tools (a superset of the opencode plugin's five memory tools); install hints point
|
|
548
|
+
at the stable line instead of `@alpha` (F27).
|
|
541
549
|
- **Phase 4 — Future, signal-gated.** Cloud `RemoteProvider` customization only on: multi-private-repo
|
|
542
550
|
sharing needs, fine-grained ACL, audit/compliance mandates · optional API-backed exporters/providers
|
|
543
551
|
for enterprise knowledge systems.
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -329,8 +329,9 @@ Example:
|
|
|
329
329
|
open-memex capture --dry-run "remember: we deploy on Fridays"`,
|
|
330
330
|
|
|
331
331
|
doctor: `Environment health check: Node version, config source, scope resolution,
|
|
332
|
-
storage writability,
|
|
333
|
-
|
|
332
|
+
storage writability, VS Code MCP enablement (settings.json + system policy),
|
|
333
|
+
then boots a real MCP server and runs initialize + tools/list against it —
|
|
334
|
+
all eleven tools must show up.
|
|
334
335
|
|
|
335
336
|
Usage: open-memex doctor
|
|
336
337
|
|
|
@@ -377,7 +378,7 @@ Usage:
|
|
|
377
378
|
Every command has its own help with description and examples:
|
|
378
379
|
open-memex <command> --help (or -h)
|
|
379
380
|
|
|
380
|
-
One-command project setup: \`open-memex init\` (or \`npx open-memex
|
|
381
|
+
One-command project setup: \`open-memex init\` (or \`npx -y open-memex init\`) detects
|
|
381
382
|
your installed editors and wires them all — user-level where the editor supports it
|
|
382
383
|
(VS Code / Cursor MCP config, opencode native plugin), so one init covers every project;
|
|
383
384
|
Visual Studio is included when the project has a solution file (its \`.mcp.json\`
|
|
@@ -392,9 +393,9 @@ confirms the detected editors and asks a couple of settings (keyword capture,
|
|
|
392
393
|
first-turn injection); \`--yes\` accepts all defaults, and non-terminal runs never prompt.
|
|
393
394
|
\`open-memex config set <key> <value>\` changes those settings after install.
|
|
394
395
|
|
|
395
|
-
Once installed globally (\`npm i -g open-memex
|
|
396
|
-
available directly: \`open-memex mcp\` starts the stdio MCP server (
|
|
397
|
-
|
|
396
|
+
Once installed globally (\`npm i -g open-memex\`) the \`open-memex\` command is
|
|
397
|
+
available directly: \`open-memex mcp\` starts the stdio MCP server (11 tools, a superset of
|
|
398
|
+
the opencode plugin's five memory_* tools); \`open-memex mcp --print-config <client>\`
|
|
398
399
|
prints a copy-paste MCP client config snippet.
|
|
399
400
|
|
|
400
401
|
Scope defaults to \`project\` (derived from cwd's git remote or path).
|
|
@@ -471,7 +472,7 @@ function resolveCliScope(flags: Record<string, string>, project: Scope): Scope {
|
|
|
471
472
|
}
|
|
472
473
|
|
|
473
474
|
/** Print a copy-paste MCP client config snippet. Requires a global install
|
|
474
|
-
* (`npm i -g open-memex
|
|
475
|
+
* (`npm i -g open-memex`) so the `open-memex` command is on PATH. */
|
|
475
476
|
function printMcpConfig(client: string): never {
|
|
476
477
|
const c = client.toLowerCase();
|
|
477
478
|
// D17: resolve the server command the same way `init` does.
|
|
@@ -547,7 +548,7 @@ function printMcpConfig(client: string): never {
|
|
|
547
548
|
}
|
|
548
549
|
if (!mc.durable) {
|
|
549
550
|
console.error(
|
|
550
|
-
`\n# note: no durable \`open-memex\` on PATH — snippet uses npx. \`npm i -g open-memex
|
|
551
|
+
`\n# note: no durable \`open-memex\` on PATH — snippet uses npx. \`npm i -g open-memex\` for faster startup.`,
|
|
551
552
|
);
|
|
552
553
|
}
|
|
553
554
|
process.exit(0);
|
|
@@ -724,7 +725,7 @@ async function main() {
|
|
|
724
725
|
return;
|
|
725
726
|
}
|
|
726
727
|
|
|
727
|
-
// `mcp` starts the stdio MCP server (
|
|
728
|
+
// `mcp` starts the stdio MCP server (11 tools; the opencode plugin exposes 5).
|
|
728
729
|
// Branched before db() — runMcpServer() does its own init, and stdout must
|
|
729
730
|
// stay clean for the MCP protocol.
|
|
730
731
|
if (cmd === "mcp") {
|
package/src/doctor.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
// Read-only except that paths() and the MCP handshake may create the (empty)
|
|
4
4
|
// data directories, exactly like a normal `open-memex mcp` start would.
|
|
5
5
|
import fs from "node:fs";
|
|
6
|
+
import os from "node:os";
|
|
6
7
|
import path from "node:path";
|
|
7
|
-
import { spawn } from "node:child_process";
|
|
8
|
+
import { spawn, execFileSync } from "node:child_process";
|
|
8
9
|
import { fileURLToPath } from "node:url";
|
|
9
10
|
import { loadConfig, configSource, DEFAULT_CONFIG } from "./config.ts";
|
|
10
11
|
import { paths } from "./paths.ts";
|
|
@@ -158,9 +159,145 @@ function mcpCheck(): Promise<Check> {
|
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
/** Parse JSON tolerating line/block comments plus trailing commas
|
|
163
|
+
* (VS Code's settings.json is JSONC). Health-check grade, not a full parser. */
|
|
164
|
+
function parseLenientJson(raw: string): Record<string, unknown> {
|
|
165
|
+
try {
|
|
166
|
+
return JSON.parse(raw) as Record<string, unknown>;
|
|
167
|
+
} catch {
|
|
168
|
+
/* fall through to comment stripping */
|
|
169
|
+
}
|
|
170
|
+
let out = "";
|
|
171
|
+
let i = 0;
|
|
172
|
+
let inStr = false;
|
|
173
|
+
let esc = false;
|
|
174
|
+
while (i < raw.length) {
|
|
175
|
+
const c = raw[i];
|
|
176
|
+
const n = raw[i + 1];
|
|
177
|
+
if (inStr) {
|
|
178
|
+
out += c;
|
|
179
|
+
if (esc) esc = false;
|
|
180
|
+
else if (c === "\\") esc = true;
|
|
181
|
+
else if (c === '"') inStr = false;
|
|
182
|
+
i++;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
if (c === '"') {
|
|
186
|
+
inStr = true;
|
|
187
|
+
out += c;
|
|
188
|
+
i++;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (c === "/" && n === "/") {
|
|
192
|
+
while (i < raw.length && raw[i] !== "\n") i++;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (c === "/" && n === "*") {
|
|
196
|
+
i += 2;
|
|
197
|
+
while (i < raw.length && !(raw[i] === "*" && raw[i + 1] === "/")) i++;
|
|
198
|
+
i += 2;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
out += c;
|
|
202
|
+
i++;
|
|
203
|
+
}
|
|
204
|
+
out = out.replace(/,\s*([}\]])/g, "$1");
|
|
205
|
+
return JSON.parse(out) as Record<string, unknown>;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function vscodeSettingsPath(): string | null {
|
|
209
|
+
const home = os.homedir();
|
|
210
|
+
if (process.platform === "win32") {
|
|
211
|
+
const appdata = process.env.APPDATA;
|
|
212
|
+
return appdata ? path.join(appdata, "Code", "User", "settings.json") : null;
|
|
213
|
+
}
|
|
214
|
+
if (process.platform === "darwin") {
|
|
215
|
+
return path.join(home, "Library", "Application Support", "Code", "User", "settings.json");
|
|
216
|
+
}
|
|
217
|
+
return path.join(home, ".config", "Code", "User", "settings.json");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** True when a Windows system policy disables MCP (value name contains "mcp",
|
|
221
|
+
* data is 0/0x0/false). Checks HKLM and HKCU policy keys. */
|
|
222
|
+
function windowsMcpPolicyDisabled(): string | null {
|
|
223
|
+
if (process.platform !== "win32") return null;
|
|
224
|
+
for (const hive of ["HKLM", "HKCU"]) {
|
|
225
|
+
try {
|
|
226
|
+
const stdout = execFileSync(
|
|
227
|
+
"reg",
|
|
228
|
+
["query", `${hive}\\SOFTWARE\\Policies\\Microsoft\\VSCode`],
|
|
229
|
+
{ encoding: "utf8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] },
|
|
230
|
+
) as string;
|
|
231
|
+
for (const line of stdout.split("\n")) {
|
|
232
|
+
const m = line.match(/^\s{2,}(\S+)\s+REG_\w+\s+(\S+)/);
|
|
233
|
+
if (m && /mcp/i.test(m[1]) && /^(0x0|0|false)$/i.test(m[2])) {
|
|
234
|
+
return `${hive}\\SOFTWARE\\Policies\\Microsoft\\VSCode!${m[1]}`;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch {
|
|
238
|
+
/* policy key absent — no policy */
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function settingsMcpDisabled(file: string): boolean {
|
|
245
|
+
try {
|
|
246
|
+
const parsed = parseLenientJson(fs.readFileSync(file, "utf8"));
|
|
247
|
+
return parsed["chat.mcp.enabled"] === false;
|
|
248
|
+
} catch {
|
|
249
|
+
return false; // unreadable file: don't claim anything
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** VS Code ignores MCP server entries entirely when MCP is switched off —
|
|
254
|
+
* either in settings.json or, on managed machines, by system policy. */
|
|
255
|
+
function vscodeMcpCheck(): Check {
|
|
256
|
+
const name = "vscode-mcp";
|
|
257
|
+
const policyHit = windowsMcpPolicyDisabled();
|
|
258
|
+
if (policyHit) {
|
|
259
|
+
return {
|
|
260
|
+
name,
|
|
261
|
+
ok: false,
|
|
262
|
+
detail:
|
|
263
|
+
`MCP is disabled by system policy (${policyHit}) — managed by your organization. ` +
|
|
264
|
+
`VS Code will ignore open-memex's MCP entry on this machine.`,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const files: string[] = [];
|
|
268
|
+
const user = vscodeSettingsPath();
|
|
269
|
+
if (user) files.push(user);
|
|
270
|
+
const ws = path.join(process.cwd(), ".vscode", "settings.json");
|
|
271
|
+
if (!files.includes(ws)) files.push(ws);
|
|
272
|
+
const found: string[] = [];
|
|
273
|
+
const disabled: string[] = [];
|
|
274
|
+
for (const f of files) {
|
|
275
|
+
if (!fs.existsSync(f)) continue;
|
|
276
|
+
found.push(f);
|
|
277
|
+
if (settingsMcpDisabled(f)) disabled.push(f);
|
|
278
|
+
}
|
|
279
|
+
if (disabled.length > 0) {
|
|
280
|
+
return {
|
|
281
|
+
name,
|
|
282
|
+
ok: false,
|
|
283
|
+
detail:
|
|
284
|
+
`chat.mcp.enabled is false in ${disabled.join(", ")} — VS Code will not load ` +
|
|
285
|
+
`MCP servers. Set it to true (or ask IT if the setting shows as managed).`,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
name,
|
|
290
|
+
ok: true,
|
|
291
|
+
detail:
|
|
292
|
+
found.length > 0
|
|
293
|
+
? `MCP enabled (checked ${found.join(", ")})`
|
|
294
|
+
: "VS Code settings not found on this machine — nothing to check",
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
161
298
|
export async function runDoctor(): Promise<boolean> {
|
|
162
299
|
console.log("open-memex doctor");
|
|
163
|
-
const checks: Check[] = [nodeCheck(), configCheck(), scopeCheck(), storageCheck()];
|
|
300
|
+
const checks: Check[] = [nodeCheck(), configCheck(), scopeCheck(), storageCheck(), vscodeMcpCheck()];
|
|
164
301
|
checks.push(await mcpCheck());
|
|
165
302
|
let allOk = true;
|
|
166
303
|
for (const c of checks) {
|