open-memex 0.5.0 → 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 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 ten 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.**
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–D13 decision log). Before changing
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` (the v2 line; alpha versions published with
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 v2 line. Never commit directly; land work via pull request
6
- from a dev branch. Alpha versions (e.g. `0.5.0-alpha.x`) live on `main`;
7
- publish them with `npm publish --tag alpha` so the npm `latest` tag only
8
- moves on stable releases.
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–D13). Changing architecture, scope semantics, lifecycle, or the protocol
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.4.1` stable release.
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` — one-time, every project picks it
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.4.1` 正式版。
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, then boots a real MCP server and runs initialize +
300
- tools/list against it — all eleven tools must show up.
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@alpha init\`) detects
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@alpha\`) the \`open-memex\` command is
362
- available directly: \`open-memex mcp\` starts the stdio MCP server (same five
363
- memory_* tools as the opencode plugin); \`open-memex mcp --print-config <client>\`
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@alpha`) so the `open-memex` command is on PATH. */
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@alpha\` for faster startup.`);
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 (same tools as the opencode plugin).
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 (planned, not yet enforced)
67
+ ## Visibility
68
68
 
69
69
  v2 frontmatter carries a separate `visibility` field (`private` | `internal` |
70
- `shared`). The intended rule: `visibility: private` inside a shared scope is
71
- **physically isolated** — written to a local-only cache directory, never
72
- under `.open-memex/` — rather than relying on `.gitignore`. This is not
73
- implemented yet; today, treat `personal` as the only confidentiality
74
- boundary and review anything you place under `.open-memex/` before pushing.
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.4.0-alpha.10)
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@alpha` 全局安装,`open-memex --version` 显示正确版本
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@alpha init` 走通
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):注意是否丢数据(预期:不丢,只影响退出码)
@@ -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) are implemented on the
6
- > `V2-dev-p2b` branch; features marked **2B** are still to be built;
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** **2B**: `open-memex pull` (always explicit, never automatic) → git fetch +
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–D24).*
196
+ *Companion design record: `docs/V2-DESIGN.md` (decisions D1–D49).*
@@ -2,8 +2,7 @@
2
2
 
3
3
  > 本文档讲的是 open-memex 的**心智模型**:你的记忆住在哪里、怎么流动、谁能看到。
4
4
  > in-repo 目录(§2、§6 的写路径)和 propose → promote → resolve 工作流(§5)
5
- > 已在 `V2-dev-p2b` 分支实现;标有 **2B** 的功能属于 Phase 2B 待实现部分,
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
- - **拉** **2B**:`open-memex pull`(必须显式,没有自动)→ git fetch + fast-forward →
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–D24 决策记录)。*
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 five memory tools —
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-memex",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Local-first memory layer and protocol for AI coding agents. Markdown source of truth, SQLite FTS5 index, zero cloud.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
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, then boots a real MCP server and runs initialize +
333
- tools/list against it — all eleven tools must show up.
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@alpha init\`) detects
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@alpha\`) the \`open-memex\` command is
396
- available directly: \`open-memex mcp\` starts the stdio MCP server (same five
397
- memory_* tools as the opencode plugin); \`open-memex mcp --print-config <client>\`
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@alpha`) so the `open-memex` command is on PATH. */
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@alpha\` for faster startup.`,
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 (same tools as the opencode plugin).
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) {