open-memex 0.3.0-alpha.1 → 0.3.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/AGENTS.md +6 -4
- package/README.md +30 -17
- package/README.zh-CN.md +29 -16
- package/dist/cli.js +37 -22
- package/dist/init.js +50 -6
- package/docs/V2-DESIGN.md +10 -0
- package/package.json +1 -1
- package/src/cli.ts +37 -21
- package/src/init.ts +55 -6
package/AGENTS.md
CHANGED
|
@@ -34,12 +34,14 @@ node --experimental-strip-types scripts\smoke-pure.ts # runs pure-logic checks
|
|
|
34
34
|
node --experimental-strip-types scripts\smoke-mcp.ts # MCP handshake + tool round-trip (temp dirs, no real data)
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
After `npm i -g open-memex
|
|
37
|
+
After `npm i -g open-memex` (or `npm link` from source), the `open-memex` bin is on
|
|
38
38
|
PATH: `open-memex mcp` starts the MCP server, `open-memex mcp --print-config <client>`
|
|
39
39
|
prints a client config snippet (client: vscode|cursor|claude|opencode|visualstudio),
|
|
40
|
-
`open-memex init [--client vscode|cursor|opencode|visualstudio] [--force] [--yes]`
|
|
41
|
-
one-command project setup (editor MCP config +
|
|
42
|
-
|
|
40
|
+
`open-memex init [--client vscode|cursor|opencode|visualstudio] [--instructions personal|project] [--force] [--yes]`
|
|
41
|
+
one-command project setup (editor MCP config + Copilot memory instructions;
|
|
42
|
+
instructions default to user-level ~/.copilot/copilot-instructions.md so the repo
|
|
43
|
+
stays clean for teammates without open-memex — D22; resolves the server command
|
|
44
|
+
at init time — npx fallback when no durable bin is on PATH, D17),
|
|
43
45
|
`open-memex config` prints the effective config, `open-memex capture --dry-run "text"`
|
|
44
46
|
previews keyword capture without writing, `open-memex doctor` runs health checks
|
|
45
47
|
(node version, config, scope resolution, storage writability, MCP handshake).
|
package/README.md
CHANGED
|
@@ -21,16 +21,15 @@ plus a generic MCP server (VS Code Copilot, Cursor, Claude Code, Visual Studio,
|
|
|
21
21
|
**npm (recommended):**
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
npm install -g open-memex
|
|
24
|
+
npm install -g open-memex
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
This installs the `0.3.0
|
|
28
|
-
`0.1.0` stable.)
|
|
27
|
+
This installs the `0.3.0` stable release.
|
|
29
28
|
|
|
30
29
|
**No install — run via npx:**
|
|
31
30
|
|
|
32
31
|
```sh
|
|
33
|
-
npx -y open-memex
|
|
32
|
+
npx -y open-memex <command> # e.g. npx -y open-memex init --client vscode
|
|
34
33
|
```
|
|
35
34
|
|
|
36
35
|
**From source** (bleeding edge, `V2-dev-p2` branch):
|
|
@@ -42,9 +41,6 @@ npm install
|
|
|
42
41
|
node --experimental-strip-types src/cli.ts <command>
|
|
43
42
|
```
|
|
44
43
|
|
|
45
|
-
> The `0.3.0-alpha` npm publish is cut from this branch — if `npx` still resolves an
|
|
46
|
-
> older alpha, install from source until the publish lands.
|
|
47
|
-
|
|
48
44
|
#### "`open-memex` is not recognized" — PATH setup
|
|
49
45
|
|
|
50
46
|
A global `npm install -g` puts the `open-memex` launcher in npm's global bin folder.
|
|
@@ -65,6 +61,15 @@ If your terminal can't find it, that folder isn't on your `PATH`:
|
|
|
65
61
|
3. No admin rights / don't want to touch `PATH`? Use the npx form above — npx
|
|
66
62
|
resolves the package itself and needs no `PATH` changes.
|
|
67
63
|
|
|
64
|
+
#### "`EBUSY` / `EPERM` on `better_sqlite3.node`" — Windows reinstall
|
|
65
|
+
|
|
66
|
+
On Windows a loaded DLL is locked: if the open-memex MCP server is running
|
|
67
|
+
(VS Code MCP panel, Cursor, etc.), `npm install -g open-memex` cannot
|
|
68
|
+
replace `better_sqlite3.node` and fails with `EBUSY` / `EPERM`. Stop the MCP
|
|
69
|
+
server first (or quit the editor), then re-run the install. If it still fails,
|
|
70
|
+
delete `node_modules/open-memex` and any `node_modules/.open-memex-*` temp
|
|
71
|
+
folders under your global npm root and install again.
|
|
72
|
+
|
|
68
73
|
### Step 2 — One-command setup for your editor
|
|
69
74
|
|
|
70
75
|
Run from your **project root** (so the project scope resolves to this repo):
|
|
@@ -74,10 +79,10 @@ Run from your **project root** (so the project scope resolves to this repo):
|
|
|
74
79
|
```sh
|
|
75
80
|
open-memex init --client vscode
|
|
76
81
|
# …or without a global install:
|
|
77
|
-
npx -y open-memex
|
|
82
|
+
npx -y open-memex init --client vscode
|
|
78
83
|
```
|
|
79
84
|
|
|
80
|
-
Writes `.vscode/mcp.json` and
|
|
85
|
+
Writes `.vscode/mcp.json` and user-level Copilot instructions, then reload the
|
|
81
86
|
window and confirm the `open-memex` server is started in Copilot Chat's MCP panel.
|
|
82
87
|
|
|
83
88
|
**Cursor:**
|
|
@@ -86,7 +91,7 @@ window and confirm the `open-memex` server is started in Copilot Chat's MCP pane
|
|
|
86
91
|
open-memex init --client cursor
|
|
87
92
|
```
|
|
88
93
|
|
|
89
|
-
Writes `.cursor/mcp.json` and
|
|
94
|
+
Writes `.cursor/mcp.json` and user-level Copilot instructions.
|
|
90
95
|
|
|
91
96
|
**opencode** (as a plain MCP consumer):
|
|
92
97
|
|
|
@@ -112,7 +117,7 @@ claude mcp add open-memex -- open-memex mcp
|
|
|
112
117
|
open-memex init --client visualstudio
|
|
113
118
|
```
|
|
114
119
|
|
|
115
|
-
Writes solution-level `.mcp.json` and
|
|
120
|
+
Writes solution-level `.mcp.json` and user-level Copilot instructions. Requires
|
|
116
121
|
Visual Studio 2022 17.14+ or Visual Studio 2026 (**Windows-only**). Visual Studio
|
|
117
122
|
also auto-discovers `.vscode/mcp.json` and `.cursor/mcp.json`, so the VS Code setup
|
|
118
123
|
above works too.
|
|
@@ -123,6 +128,12 @@ above works too.
|
|
|
123
128
|
|
|
124
129
|
`init` notes:
|
|
125
130
|
|
|
131
|
+
- The Copilot memory instructions default to **user-level**
|
|
132
|
+
(`~/.copilot/copilot-instructions.md`; `%USERPROFILE%\copilot-instructions.md`
|
|
133
|
+
for Visual Studio) — they apply to all your projects and are never checked
|
|
134
|
+
into a repo, so teammates without open-memex see nothing and nothing breaks
|
|
135
|
+
for them. `--instructions project` writes `.github/copilot-instructions.md`
|
|
136
|
+
instead, for teams where everyone uses open-memex.
|
|
126
137
|
- On a terminal it interactively asks which editor to set up, whether to enable
|
|
127
138
|
keyword auto-capture, and whether to inject memories on the first turn.
|
|
128
139
|
`--yes` accepts the defaults; scripts / non-TTY never prompt (editor defaults to
|
|
@@ -130,8 +141,8 @@ above works too.
|
|
|
130
141
|
- Existing config files are **merged, never clobbered** — re-running is safe.
|
|
131
142
|
`--force` overwrites.
|
|
132
143
|
- With no durable `open-memex` on `PATH` (e.g. one-shot npx), `init` writes an
|
|
133
|
-
`npx -y open-memex
|
|
134
|
-
working. `npm i -g open-memex
|
|
144
|
+
`npx -y open-memex mcp` server command into the config so the setup keeps
|
|
145
|
+
working. `npm i -g open-memex` + `open-memex init --force` switches to the
|
|
135
146
|
faster direct command later.
|
|
136
147
|
|
|
137
148
|
### Step 3 — Verify it works
|
|
@@ -237,6 +248,8 @@ open-memex config set <key> <value> # change a setting
|
|
|
237
248
|
open-memex doctor # environment health check
|
|
238
249
|
open-memex capture --dry-run "记住我喜欢简洁的回答" # preview keyword capture
|
|
239
250
|
open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
|
|
251
|
+
open-memex --help # this reference
|
|
252
|
+
open-memex --version # installed version
|
|
240
253
|
```
|
|
241
254
|
|
|
242
255
|
Memory operations:
|
|
@@ -272,7 +285,7 @@ no host-specific plugin needed. Any MCP client can use open-memex.
|
|
|
272
285
|
|
|
273
286
|
```sh
|
|
274
287
|
open-memex mcp # after a global install
|
|
275
|
-
npx -y open-memex
|
|
288
|
+
npx -y open-memex mcp # no install needed
|
|
276
289
|
```
|
|
277
290
|
|
|
278
291
|
The project scope is resolved from the process working directory, so configure the
|
|
@@ -280,16 +293,16 @@ server with cwd set to your project root (`init` handles this for you).
|
|
|
280
293
|
|
|
281
294
|
> **Note:** MCP is request/response — it gives the agent tools, not the opencode
|
|
282
295
|
> plugin's automatic keyword capture or first-turn context injection. Proactive
|
|
283
|
-
> memory use depends on the agent's instructions (the
|
|
296
|
+
> memory use depends on the agent's instructions (the Copilot instructions
|
|
284
297
|
> that `init` writes).
|
|
285
298
|
|
|
286
299
|
## Roadmap
|
|
287
300
|
|
|
288
|
-
**`0.3.0
|
|
301
|
+
**`0.3.0` (this release):** generic MCP server, `open-memex` bin/CLI, one-command
|
|
289
302
|
`init` setup, Chinese keyword capture with personal/project routing, `config` /
|
|
290
303
|
`capture --dry-run` / `doctor` helpers, Visual Studio support.
|
|
291
304
|
|
|
292
|
-
**Coming — `0.
|
|
305
|
+
**Coming — `0.4.0`:** team sync — shared memory via git (`propose` / `promote` /
|
|
293
306
|
`resolve` workflow, in-repo memory dir), 1–2 colleague pilot.
|
|
294
307
|
|
|
295
308
|
**Coming — `0.3.0` (stable):** org layer — org memory repo, curator convention,
|
package/README.zh-CN.md
CHANGED
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
**npm(推荐):**
|
|
22
22
|
|
|
23
23
|
```sh
|
|
24
|
-
npm install -g open-memex
|
|
24
|
+
npm install -g open-memex
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
安装的是 `0.3.0
|
|
27
|
+
安装的是 `0.3.0` 正式版。
|
|
28
28
|
|
|
29
29
|
**免安装——用 npx 直接跑:**
|
|
30
30
|
|
|
31
31
|
```sh
|
|
32
|
-
npx -y open-memex
|
|
32
|
+
npx -y open-memex <命令> # 例如 npx -y open-memex init --client vscode
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
**从源码安装**(最新开发版,`V2-dev-p2` 分支):
|
|
@@ -41,9 +41,6 @@ npm install
|
|
|
41
41
|
node --experimental-strip-types src/cli.ts <命令>
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
> `0.3.0-alpha` 的 npm 发布从该分支切出——如果 npx 还解析到旧的 alpha 版,
|
|
45
|
-
> 请先用源码安装,等发布落地。
|
|
46
|
-
|
|
47
44
|
#### 提示 "'open-memex' 不是内部命令"?——PATH 设置
|
|
48
45
|
|
|
49
46
|
`npm install -g` 会把 `open-memex` 启动器放到 npm 的全局 bin 目录。
|
|
@@ -63,6 +60,14 @@ node --experimental-strip-types src/cli.ts <命令>
|
|
|
63
60
|
3. 没有管理员权限 / 不想动 `PATH`?用上面的 npx 形式——npx 自己解析包,
|
|
64
61
|
不需要改 `PATH`。
|
|
65
62
|
|
|
63
|
+
#### Windows 重装报 "`EBUSY` / `EPERM`(`better_sqlite3.node`)"
|
|
64
|
+
|
|
65
|
+
Windows 下被进程加载的 DLL 是锁死的:如果 open-memex MCP server 正在运行
|
|
66
|
+
(VS Code MCP 面板、Cursor 等),`npm install -g open-memex` 替换不了
|
|
67
|
+
`better_sqlite3.node`,就会报 `EBUSY` / `EPERM`。先停掉 MCP server
|
|
68
|
+
(或退出编辑器),再重跑安装。还不行的话,手动删掉全局 npm 目录下的
|
|
69
|
+
`node_modules/open-memex` 和 `node_modules/.open-memex-*` 临时目录,再装。
|
|
70
|
+
|
|
66
71
|
### 第二步——给你的编辑器一键配置
|
|
67
72
|
|
|
68
73
|
在**项目根目录**下运行(这样 project scope 会解析到这个仓库):
|
|
@@ -72,10 +77,10 @@ node --experimental-strip-types src/cli.ts <命令>
|
|
|
72
77
|
```sh
|
|
73
78
|
open-memex init --client vscode
|
|
74
79
|
# ……没装全局包的话:
|
|
75
|
-
npx -y open-memex
|
|
80
|
+
npx -y open-memex init --client vscode
|
|
76
81
|
```
|
|
77
82
|
|
|
78
|
-
自动写 `.vscode/mcp.json`
|
|
83
|
+
自动写 `.vscode/mcp.json` 和用户级 Copilot instructions,然后重新加载窗口,
|
|
79
84
|
在 Copilot Chat 的 MCP 面板里确认 `open-memex` server 已启动。
|
|
80
85
|
|
|
81
86
|
**Cursor:**
|
|
@@ -84,7 +89,7 @@ npx -y open-memex@alpha init --client vscode
|
|
|
84
89
|
open-memex init --client cursor
|
|
85
90
|
```
|
|
86
91
|
|
|
87
|
-
自动写 `.cursor/mcp.json`
|
|
92
|
+
自动写 `.cursor/mcp.json` 和用户级 Copilot instructions。
|
|
88
93
|
|
|
89
94
|
**opencode**(作为普通 MCP 客户端):
|
|
90
95
|
|
|
@@ -110,7 +115,7 @@ claude mcp add open-memex -- open-memex mcp
|
|
|
110
115
|
open-memex init --client visualstudio
|
|
111
116
|
```
|
|
112
117
|
|
|
113
|
-
写 solution 级 `.mcp.json`
|
|
118
|
+
写 solution 级 `.mcp.json` 和用户级 Copilot instructions。需要
|
|
114
119
|
Visual Studio 2022 17.14+ 或 Visual Studio 2026(**仅 Windows**)。
|
|
115
120
|
Visual Studio 也会自动发现 `.vscode/mcp.json` 和 `.cursor/mcp.json`,
|
|
116
121
|
所以上面的 VS Code 配置同样可用。
|
|
@@ -120,14 +125,20 @@ Visual Studio 也会自动发现 `.vscode/mcp.json` 和 `.cursor/mcp.json`,
|
|
|
120
125
|
|
|
121
126
|
`init` 说明:
|
|
122
127
|
|
|
128
|
+
- Copilot 记忆 instructions 默认写到**用户级**
|
|
129
|
+
(`~/.copilot/copilot-instructions.md`;Visual Studio 是
|
|
130
|
+
`%USERPROFILE%\copilot-instructions.md`)——所有项目生效,永不 checkin
|
|
131
|
+
到 repo,没装 open-memex 的同事看不到、也不会出错。团队人人都用
|
|
132
|
+
open-memex 时可用 `--instructions project` 改写
|
|
133
|
+
`.github/copilot-instructions.md`。
|
|
123
134
|
- 在终端里会交互式询问:配哪个编辑器、是否开启关键词自动捕获、
|
|
124
135
|
是否在首轮注入记忆。`--yes` 全用默认值;脚本 / 非 TTY 环境不提问
|
|
125
136
|
(编辑器默认 VS Code)。
|
|
126
137
|
- 已有配置文件会被**合并,不会被覆盖**——重复运行是安全的。
|
|
127
138
|
`--force` 强制覆盖。
|
|
128
139
|
- 如果 `PATH` 上没有可用的 `open-memex`(比如一次性 npx),`init` 会把
|
|
129
|
-
`npx -y open-memex
|
|
130
|
-
以后 `npm i -g open-memex
|
|
140
|
+
`npx -y open-memex mcp` 写进配置,配置照样能用。
|
|
141
|
+
以后 `npm i -g open-memex` + `open-memex init --force` 可切换到更快
|
|
131
142
|
的直接调用。
|
|
132
143
|
|
|
133
144
|
### 第三步——验证
|
|
@@ -236,6 +247,8 @@ open-memex config set <key> <value> # 改设置
|
|
|
236
247
|
open-memex doctor # 环境健康检查
|
|
237
248
|
open-memex capture --dry-run "记住我喜欢简洁的回答" # 预览关键词捕获
|
|
238
249
|
open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
|
|
250
|
+
open-memex --help # 本帮助
|
|
251
|
+
open-memex --version # 已安装版本
|
|
239
252
|
```
|
|
240
253
|
|
|
241
254
|
记忆操作:
|
|
@@ -272,7 +285,7 @@ CLI 跑在 Node 22 下。从源码 checkout 使用时走内置的实验性 TypeS
|
|
|
272
285
|
|
|
273
286
|
```sh
|
|
274
287
|
open-memex mcp # 全局安装后
|
|
275
|
-
npx -y open-memex
|
|
288
|
+
npx -y open-memex mcp # 免安装
|
|
276
289
|
```
|
|
277
290
|
|
|
278
291
|
project scope 从进程工作目录解析,所以配置 server 时 cwd 要指向项目根目录
|
|
@@ -280,15 +293,15 @@ project scope 从进程工作目录解析,所以配置 server 时 cwd 要指
|
|
|
280
293
|
|
|
281
294
|
> **注意:** MCP 是请求/响应式的——它给 agent 提供 tools,但没有 opencode
|
|
282
295
|
> 插件的关键词自动捕获和首轮上下文注入。想让 agent 主动用记忆,
|
|
283
|
-
> 靠的是 agent 的 instructions(`init` 写的
|
|
296
|
+
> 靠的是 agent 的 instructions(`init` 写的 Copilot instructions)。
|
|
284
297
|
|
|
285
298
|
## 路线图(Roadmap)
|
|
286
299
|
|
|
287
|
-
**`0.3.0
|
|
300
|
+
**`0.3.0`(本版):** 通用 MCP server、`open-memex` bin/CLI、
|
|
288
301
|
一键 `init` 配置、中文关键词捕获(含 personal/project 路由)、
|
|
289
302
|
`config` / `capture --dry-run` / `doctor` 助手命令、Visual Studio 支持。
|
|
290
303
|
|
|
291
|
-
**Coming —— `0.
|
|
304
|
+
**Coming —— `0.4.0`:** 团队同步——用 git 做共享记忆
|
|
292
305
|
(`propose` / `promote` / `resolve` 工作流、仓库内记忆目录),
|
|
293
306
|
找 1–2 个同事做 pilot。
|
|
294
307
|
|
package/dist/cli.js
CHANGED
|
@@ -13,32 +13,38 @@ import { paths } from "./paths.js";
|
|
|
13
13
|
import { redact } from "./redact.js";
|
|
14
14
|
import { resolveMcpCommand } from "./init.js";
|
|
15
15
|
import fs from "node:fs";
|
|
16
|
-
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import { fileURLToPath } from "node:url";
|
|
18
|
+
function usage(exitCode = 1) {
|
|
17
19
|
console.log(`open-memex CLI
|
|
18
20
|
|
|
19
21
|
Usage:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
open-memex where
|
|
23
|
+
open-memex list [--scope project|personal] [--type T] [--limit N]
|
|
24
|
+
open-memex search "query" [--scope project|personal|both] [--type T] [--limit N]
|
|
25
|
+
open-memex add "content" [--scope project|personal] [--type T] [--tag t1,t2]
|
|
26
|
+
open-memex supersede <id> "new content" [--type T] [--tag t1,t2]
|
|
27
|
+
open-memex status <id> active|deprecated|retracted|archived
|
|
28
|
+
open-memex forget <id>
|
|
29
|
+
open-memex reindex
|
|
30
|
+
open-memex scopes
|
|
31
|
+
open-memex migrate [--from <key>] [--to <key>]
|
|
30
32
|
[--dry-run] [--on-conflict newer|overwrite|skip]
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
open-memex migrate --to-v2 [--dry-run]
|
|
34
|
+
open-memex mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
|
|
35
|
+
open-memex init [--client vscode|cursor|opencode|visualstudio]
|
|
36
|
+
[--instructions personal|project] [--force] [--yes]
|
|
37
|
+
open-memex config [set <key> <value>]
|
|
38
|
+
open-memex capture --dry-run "text"
|
|
39
|
+
open-memex doctor
|
|
37
40
|
|
|
38
41
|
One-command project setup: \`open-memex init\` (or \`npx open-memex@alpha init\`) writes
|
|
39
42
|
the MCP config for your editor (\`.vscode/mcp.json\`, \`.cursor/mcp.json\`,
|
|
40
|
-
\`opencode.jsonc\`, or Visual Studio's solution-level \`.mcp.json\`)
|
|
41
|
-
|
|
43
|
+
\`opencode.jsonc\`, or Visual Studio's solution-level \`.mcp.json\`) — no copy-paste
|
|
44
|
+
needed. The Copilot memory instructions default to your user-level
|
|
45
|
+
\`~/.copilot/copilot-instructions.md\` (all projects, never checked into a repo);
|
|
46
|
+
\`--instructions project\` writes \`.github/copilot-instructions.md\` instead for
|
|
47
|
+
teams where everyone uses open-memex.
|
|
42
48
|
Existing files are merged, never clobbered; re-running is safe. On a terminal it
|
|
43
49
|
asks which editor to set up and a couple of settings (keyword capture, first-turn
|
|
44
50
|
injection); \`--yes\` accepts all defaults, and non-terminal runs never prompt.
|
|
@@ -58,7 +64,7 @@ git remote after memories were already stored under the cwd-based key.
|
|
|
58
64
|
\`migrate --to-v2\` converts v1 memory files to the v2 format (§19):
|
|
59
65
|
user→personal scope rename, epoch→RFC 3339 times, priority→importance,
|
|
60
66
|
type: instruction→role split. Always preview with --dry-run first.`);
|
|
61
|
-
process.exit(
|
|
67
|
+
process.exit(exitCode);
|
|
62
68
|
}
|
|
63
69
|
function parseFlags(argv) {
|
|
64
70
|
const out = {};
|
|
@@ -147,8 +153,16 @@ function printMcpConfig(client) {
|
|
|
147
153
|
}
|
|
148
154
|
async function main() {
|
|
149
155
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
150
|
-
if (!cmd)
|
|
151
|
-
usage();
|
|
156
|
+
if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help")
|
|
157
|
+
usage(0);
|
|
158
|
+
if (cmd === "--version" || cmd === "-v") {
|
|
159
|
+
// package.json sits two levels above this file in both layouts
|
|
160
|
+
// (src/cli.ts and dist/cli.js).
|
|
161
|
+
const root = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
162
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
|
|
163
|
+
console.log(`open-memex ${pkg.version}`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
152
166
|
const cfg = loadConfig();
|
|
153
167
|
const project = resolveProjectScope(process.cwd());
|
|
154
168
|
// `migrate --to-v2` is a pure file operation (V2-DESIGN §19) — it runs
|
|
@@ -184,6 +198,7 @@ async function main() {
|
|
|
184
198
|
client: flags["client"],
|
|
185
199
|
force: flags["force"] === "true",
|
|
186
200
|
yes: flags["yes"] === "true",
|
|
201
|
+
instructions: flags["instructions"],
|
|
187
202
|
});
|
|
188
203
|
return;
|
|
189
204
|
}
|
package/dist/init.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// `open-memex init` — one-command project setup (§17 adoption path).
|
|
2
2
|
// Pure file operation: no DB, no network. Safe to run in any directory.
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { execFileSync } from "node:child_process";
|
|
6
7
|
import { createInterface } from "node:readline/promises";
|
|
@@ -35,6 +36,9 @@ export function resolveMcpCommand() {
|
|
|
35
36
|
const INSTRUCTIONS = `${MARKER}
|
|
36
37
|
# OpenMemex memory
|
|
37
38
|
|
|
39
|
+
> Applies only when the \`open-memex\` MCP server is available in this session
|
|
40
|
+
> (the \`memory_*\` tools exist). Otherwise ignore this section.
|
|
41
|
+
|
|
38
42
|
You have a local memory MCP server (\`open-memex\`) with five tools:
|
|
39
43
|
\`memory_add\`, \`memory_search\`, \`memory_list\`, \`memory_supersede\`, \`memory_forget\`.
|
|
40
44
|
|
|
@@ -174,9 +178,21 @@ function writeVisualStudioMcpJson(root, force) {
|
|
|
174
178
|
}
|
|
175
179
|
return file;
|
|
176
180
|
}
|
|
177
|
-
function writeInstructions(root) {
|
|
178
|
-
const
|
|
179
|
-
|
|
181
|
+
function writeInstructions(root, scope, client) {
|
|
182
|
+
const file = scope === "project"
|
|
183
|
+
? path.join(root, ".github", "copilot-instructions.md")
|
|
184
|
+
: client === "visualstudio"
|
|
185
|
+
? path.join(os.homedir(), "copilot-instructions.md")
|
|
186
|
+
: path.join(os.homedir(), ".copilot", "copilot-instructions.md");
|
|
187
|
+
if (scope === "personal") {
|
|
188
|
+
// A previous project-scoped init may have left the section behind — flag it
|
|
189
|
+
// so the repo can go back to being open-memex-free for teammates.
|
|
190
|
+
const proj = path.join(root, ".github", "copilot-instructions.md");
|
|
191
|
+
if (fs.existsSync(proj) && fs.readFileSync(proj, "utf8").includes(MARKER)) {
|
|
192
|
+
console.log(` ! project-level instructions still present at ${proj}`);
|
|
193
|
+
console.log(` remove the open-memex section there to keep the repo clean.`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
180
196
|
if (fs.existsSync(file)) {
|
|
181
197
|
const cur = fs.readFileSync(file, "utf8");
|
|
182
198
|
if (cur.includes(MARKER)) {
|
|
@@ -186,7 +202,7 @@ function writeInstructions(root) {
|
|
|
186
202
|
fs.writeFileSync(file, cur.replace(/\s+$/, "") + "\n\n" + INSTRUCTIONS);
|
|
187
203
|
}
|
|
188
204
|
else {
|
|
189
|
-
fs.mkdirSync(
|
|
205
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
190
206
|
fs.writeFileSync(file, INSTRUCTIONS);
|
|
191
207
|
}
|
|
192
208
|
console.log(` + ${file}`);
|
|
@@ -237,6 +253,21 @@ async function promptClient() {
|
|
|
237
253
|
rl.close();
|
|
238
254
|
}
|
|
239
255
|
}
|
|
256
|
+
/** D22: where the Copilot memory instructions live. Personal (default) is the
|
|
257
|
+
* Copilot user-level location — all projects, never checked in. */
|
|
258
|
+
async function promptInstructionsScope() {
|
|
259
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
260
|
+
try {
|
|
261
|
+
console.log("Where should the Copilot memory instructions live?");
|
|
262
|
+
console.log(" 1) personal — user-level, all projects, never checked into a repo");
|
|
263
|
+
console.log(" 2) project — .github/copilot-instructions.md, shared with the repo");
|
|
264
|
+
const ans = (await rl.question("Choice [1]: ")).trim();
|
|
265
|
+
return ans === "2" ? "project" : "personal";
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
rl.close();
|
|
269
|
+
}
|
|
270
|
+
}
|
|
240
271
|
export async function initProject(opts) {
|
|
241
272
|
const interactive = !opts.yes && !!process.stdin.isTTY && !!process.stdout.isTTY;
|
|
242
273
|
let client = normalizeClient(opts.client ?? "");
|
|
@@ -248,11 +279,22 @@ export async function initProject(opts) {
|
|
|
248
279
|
client = (await promptClient()) ?? "";
|
|
249
280
|
if (!client && !interactive)
|
|
250
281
|
client = "vscode"; // historical default for scripts / one-shot npx
|
|
282
|
+
let scope = "personal";
|
|
283
|
+
if (opts.instructions) {
|
|
284
|
+
if (opts.instructions !== "personal" && opts.instructions !== "project") {
|
|
285
|
+
console.error(`unknown --instructions "${opts.instructions}" (personal|project)`);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
scope = opts.instructions;
|
|
289
|
+
}
|
|
290
|
+
else if (interactive) {
|
|
291
|
+
scope = await promptInstructionsScope();
|
|
292
|
+
}
|
|
251
293
|
if (interactive) {
|
|
252
294
|
// Install-time settings (D19). Non-default answers persist to the JSONC
|
|
253
295
|
// config file; `open-memex config set` changes them later.
|
|
254
296
|
const patch = {};
|
|
255
|
-
const keywordCaptureEnabled = await askBool("Auto-capture keywords like
|
|
297
|
+
const keywordCaptureEnabled = await askBool("Auto-capture keywords like remember… / note that… into memory?", DEFAULT_CONFIG.keywordCaptureEnabled);
|
|
256
298
|
if (keywordCaptureEnabled !== DEFAULT_CONFIG.keywordCaptureEnabled)
|
|
257
299
|
patch.keywordCaptureEnabled = keywordCaptureEnabled;
|
|
258
300
|
const injectOnFirstTurn = await askBool("Inject relevant memories when a session starts?", DEFAULT_CONFIG.injectOnFirstTurn);
|
|
@@ -269,8 +311,10 @@ export async function initProject(opts) {
|
|
|
269
311
|
writeMcpJson(root, client, opts.force);
|
|
270
312
|
// copilot-instructions.md is VS Code/Cursor-shaped; opencode as a plain MCP
|
|
271
313
|
// consumer already gets the guidance from the tool descriptions (D16).
|
|
314
|
+
// D22: personal scope (default) writes to the Copilot user-level location
|
|
315
|
+
// so the repo stays clean for teammates without open-memex.
|
|
272
316
|
if (client !== "opencode")
|
|
273
|
-
writeInstructions(root);
|
|
317
|
+
writeInstructions(root, scope, client);
|
|
274
318
|
}
|
|
275
319
|
else {
|
|
276
320
|
console.log(" - editor setup skipped");
|
package/docs/V2-DESIGN.md
CHANGED
|
@@ -587,6 +587,16 @@ requirement: personal data never touches third-party services). Benchmarks to tr
|
|
|
587
587
|
/ `npm run mcp` run `src/` directly); `doctor`'s MCP self-check resolves its server
|
|
588
588
|
entry the same way it is running (`dist/mcp.js` vs `src/mcp.ts`). The opencode
|
|
589
589
|
native plugin still loads `src/index.ts` (Bun strips types anywhere). 2026-09-27.*
|
|
590
|
+
- **D22** — `init` writes the Copilot memory instructions to the **user level** by
|
|
591
|
+
default (`~/.copilot/copilot-instructions.md`; `%USERPROFILE%\copilot-
|
|
592
|
+
instructions.md` for Visual Studio 2026) instead of the repo-level
|
|
593
|
+
`.github/copilot-instructions.md`. *Rationale: the repo-level file is checked in,
|
|
594
|
+
so teammates without open-memex get Copilot errors about missing `memory_*`
|
|
595
|
+
tools. The user-level location is GitHub's official personal-instructions slot
|
|
596
|
+
(highest priority, all projects, never in a repo). `--instructions project`
|
|
597
|
+
keeps the old repo-level behavior for teams where everyone uses open-memex.
|
|
598
|
+
The instructions carry a guard clause ("ignore this section when the
|
|
599
|
+
`open-memex` MCP server is not available") as cheap insurance. 2026-09-27.*
|
|
590
600
|
|
|
591
601
|
## Open Questions
|
|
592
602
|
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -20,33 +20,39 @@ import { paths } from "./paths.ts";
|
|
|
20
20
|
import { redact } from "./redact.ts";
|
|
21
21
|
import { resolveMcpCommand } from "./init.ts";
|
|
22
22
|
import fs from "node:fs";
|
|
23
|
+
import path from "node:path";
|
|
24
|
+
import { fileURLToPath } from "node:url";
|
|
23
25
|
|
|
24
|
-
function usage(): never {
|
|
26
|
+
function usage(exitCode = 1): never {
|
|
25
27
|
console.log(`open-memex CLI
|
|
26
28
|
|
|
27
29
|
Usage:
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
open-memex where
|
|
31
|
+
open-memex list [--scope project|personal] [--type T] [--limit N]
|
|
32
|
+
open-memex search "query" [--scope project|personal|both] [--type T] [--limit N]
|
|
33
|
+
open-memex add "content" [--scope project|personal] [--type T] [--tag t1,t2]
|
|
34
|
+
open-memex supersede <id> "new content" [--type T] [--tag t1,t2]
|
|
35
|
+
open-memex status <id> active|deprecated|retracted|archived
|
|
36
|
+
open-memex forget <id>
|
|
37
|
+
open-memex reindex
|
|
38
|
+
open-memex scopes
|
|
39
|
+
open-memex migrate [--from <key>] [--to <key>]
|
|
38
40
|
[--dry-run] [--on-conflict newer|overwrite|skip]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
open-memex migrate --to-v2 [--dry-run]
|
|
42
|
+
open-memex mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
|
|
43
|
+
open-memex init [--client vscode|cursor|opencode|visualstudio]
|
|
44
|
+
[--instructions personal|project] [--force] [--yes]
|
|
45
|
+
open-memex config [set <key> <value>]
|
|
46
|
+
open-memex capture --dry-run "text"
|
|
47
|
+
open-memex doctor
|
|
45
48
|
|
|
46
49
|
One-command project setup: \`open-memex init\` (or \`npx open-memex@alpha init\`) writes
|
|
47
50
|
the MCP config for your editor (\`.vscode/mcp.json\`, \`.cursor/mcp.json\`,
|
|
48
|
-
\`opencode.jsonc\`, or Visual Studio's solution-level \`.mcp.json\`)
|
|
49
|
-
|
|
51
|
+
\`opencode.jsonc\`, or Visual Studio's solution-level \`.mcp.json\`) — no copy-paste
|
|
52
|
+
needed. The Copilot memory instructions default to your user-level
|
|
53
|
+
\`~/.copilot/copilot-instructions.md\` (all projects, never checked into a repo);
|
|
54
|
+
\`--instructions project\` writes \`.github/copilot-instructions.md\` instead for
|
|
55
|
+
teams where everyone uses open-memex.
|
|
50
56
|
Existing files are merged, never clobbered; re-running is safe. On a terminal it
|
|
51
57
|
asks which editor to set up and a couple of settings (keyword capture, first-turn
|
|
52
58
|
injection); \`--yes\` accepts all defaults, and non-terminal runs never prompt.
|
|
@@ -66,7 +72,7 @@ git remote after memories were already stored under the cwd-based key.
|
|
|
66
72
|
\`migrate --to-v2\` converts v1 memory files to the v2 format (§19):
|
|
67
73
|
user→personal scope rename, epoch→RFC 3339 times, priority→importance,
|
|
68
74
|
type: instruction→role split. Always preview with --dry-run first.`);
|
|
69
|
-
process.exit(
|
|
75
|
+
process.exit(exitCode);
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
function parseFlags(argv: string[]): Record<string, string> {
|
|
@@ -179,7 +185,16 @@ function printMcpConfig(client: string): never {
|
|
|
179
185
|
|
|
180
186
|
async function main() {
|
|
181
187
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
182
|
-
if (!cmd) usage();
|
|
188
|
+
if (!cmd || cmd === "--help" || cmd === "-h" || cmd === "help") usage(0);
|
|
189
|
+
|
|
190
|
+
if (cmd === "--version" || cmd === "-v") {
|
|
191
|
+
// package.json sits two levels above this file in both layouts
|
|
192
|
+
// (src/cli.ts and dist/cli.js).
|
|
193
|
+
const root = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
194
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
|
|
195
|
+
console.log(`open-memex ${pkg.version}`);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
183
198
|
|
|
184
199
|
const cfg = loadConfig();
|
|
185
200
|
const project = resolveProjectScope(process.cwd());
|
|
@@ -225,6 +240,7 @@ async function main() {
|
|
|
225
240
|
client: flags["client"],
|
|
226
241
|
force: flags["force"] === "true",
|
|
227
242
|
yes: flags["yes"] === "true",
|
|
243
|
+
instructions: flags["instructions"],
|
|
228
244
|
});
|
|
229
245
|
return;
|
|
230
246
|
}
|
package/src/init.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// `open-memex init` — one-command project setup (§17 adoption path).
|
|
2
2
|
// Pure file operation: no DB, no network. Safe to run in any directory.
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { execFileSync } from "node:child_process";
|
|
6
7
|
import { createInterface } from "node:readline/promises";
|
|
@@ -46,6 +47,9 @@ export function resolveMcpCommand(): McpCommand {
|
|
|
46
47
|
const INSTRUCTIONS = `${MARKER}
|
|
47
48
|
# OpenMemex memory
|
|
48
49
|
|
|
50
|
+
> Applies only when the \`open-memex\` MCP server is available in this session
|
|
51
|
+
> (the \`memory_*\` tools exist). Otherwise ignore this section.
|
|
52
|
+
|
|
49
53
|
You have a local memory MCP server (\`open-memex\`) with five tools:
|
|
50
54
|
\`memory_add\`, \`memory_search\`, \`memory_list\`, \`memory_supersede\`, \`memory_forget\`.
|
|
51
55
|
|
|
@@ -186,9 +190,26 @@ function writeVisualStudioMcpJson(root: string, force: boolean): string | null {
|
|
|
186
190
|
return file;
|
|
187
191
|
}
|
|
188
192
|
|
|
189
|
-
function writeInstructions(
|
|
190
|
-
|
|
191
|
-
|
|
193
|
+
function writeInstructions(
|
|
194
|
+
root: string,
|
|
195
|
+
scope: "personal" | "project",
|
|
196
|
+
client: string,
|
|
197
|
+
): string {
|
|
198
|
+
const file =
|
|
199
|
+
scope === "project"
|
|
200
|
+
? path.join(root, ".github", "copilot-instructions.md")
|
|
201
|
+
: client === "visualstudio"
|
|
202
|
+
? path.join(os.homedir(), "copilot-instructions.md")
|
|
203
|
+
: path.join(os.homedir(), ".copilot", "copilot-instructions.md");
|
|
204
|
+
if (scope === "personal") {
|
|
205
|
+
// A previous project-scoped init may have left the section behind — flag it
|
|
206
|
+
// so the repo can go back to being open-memex-free for teammates.
|
|
207
|
+
const proj = path.join(root, ".github", "copilot-instructions.md");
|
|
208
|
+
if (fs.existsSync(proj) && fs.readFileSync(proj, "utf8").includes(MARKER)) {
|
|
209
|
+
console.log(` ! project-level instructions still present at ${proj}`);
|
|
210
|
+
console.log(` remove the open-memex section there to keep the repo clean.`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
192
213
|
if (fs.existsSync(file)) {
|
|
193
214
|
const cur = fs.readFileSync(file, "utf8");
|
|
194
215
|
if (cur.includes(MARKER)) {
|
|
@@ -197,7 +218,7 @@ function writeInstructions(root: string): string {
|
|
|
197
218
|
}
|
|
198
219
|
fs.writeFileSync(file, cur.replace(/\s+$/, "") + "\n\n" + INSTRUCTIONS);
|
|
199
220
|
} else {
|
|
200
|
-
fs.mkdirSync(
|
|
221
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
201
222
|
fs.writeFileSync(file, INSTRUCTIONS);
|
|
202
223
|
}
|
|
203
224
|
console.log(` + ${file}`);
|
|
@@ -254,10 +275,26 @@ async function promptClient(): Promise<string | null> {
|
|
|
254
275
|
}
|
|
255
276
|
}
|
|
256
277
|
|
|
278
|
+
/** D22: where the Copilot memory instructions live. Personal (default) is the
|
|
279
|
+
* Copilot user-level location — all projects, never checked in. */
|
|
280
|
+
async function promptInstructionsScope(): Promise<"personal" | "project"> {
|
|
281
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
282
|
+
try {
|
|
283
|
+
console.log("Where should the Copilot memory instructions live?");
|
|
284
|
+
console.log(" 1) personal — user-level, all projects, never checked into a repo");
|
|
285
|
+
console.log(" 2) project — .github/copilot-instructions.md, shared with the repo");
|
|
286
|
+
const ans = (await rl.question("Choice [1]: ")).trim();
|
|
287
|
+
return ans === "2" ? "project" : "personal";
|
|
288
|
+
} finally {
|
|
289
|
+
rl.close();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
257
293
|
export async function initProject(opts: {
|
|
258
294
|
client?: string;
|
|
259
295
|
force: boolean;
|
|
260
296
|
yes: boolean;
|
|
297
|
+
instructions?: string;
|
|
261
298
|
}): Promise<void> {
|
|
262
299
|
const interactive = !opts.yes && !!process.stdin.isTTY && !!process.stdout.isTTY;
|
|
263
300
|
let client = normalizeClient(opts.client ?? "");
|
|
@@ -267,12 +304,22 @@ export async function initProject(opts: {
|
|
|
267
304
|
}
|
|
268
305
|
if (!client && interactive) client = (await promptClient()) ?? "";
|
|
269
306
|
if (!client && !interactive) client = "vscode"; // historical default for scripts / one-shot npx
|
|
307
|
+
let scope: "personal" | "project" = "personal";
|
|
308
|
+
if (opts.instructions) {
|
|
309
|
+
if (opts.instructions !== "personal" && opts.instructions !== "project") {
|
|
310
|
+
console.error(`unknown --instructions "${opts.instructions}" (personal|project)`);
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
scope = opts.instructions;
|
|
314
|
+
} else if (interactive) {
|
|
315
|
+
scope = await promptInstructionsScope();
|
|
316
|
+
}
|
|
270
317
|
if (interactive) {
|
|
271
318
|
// Install-time settings (D19). Non-default answers persist to the JSONC
|
|
272
319
|
// config file; `open-memex config set` changes them later.
|
|
273
320
|
const patch: Record<string, unknown> = {};
|
|
274
321
|
const keywordCaptureEnabled = await askBool(
|
|
275
|
-
"Auto-capture keywords like
|
|
322
|
+
"Auto-capture keywords like remember… / note that… into memory?",
|
|
276
323
|
DEFAULT_CONFIG.keywordCaptureEnabled,
|
|
277
324
|
);
|
|
278
325
|
if (keywordCaptureEnabled !== DEFAULT_CONFIG.keywordCaptureEnabled)
|
|
@@ -296,7 +343,9 @@ export async function initProject(opts: {
|
|
|
296
343
|
writeMcpJson(root, client, opts.force);
|
|
297
344
|
// copilot-instructions.md is VS Code/Cursor-shaped; opencode as a plain MCP
|
|
298
345
|
// consumer already gets the guidance from the tool descriptions (D16).
|
|
299
|
-
|
|
346
|
+
// D22: personal scope (default) writes to the Copilot user-level location
|
|
347
|
+
// so the repo stays clean for teammates without open-memex.
|
|
348
|
+
if (client !== "opencode") writeInstructions(root, scope, client);
|
|
300
349
|
} else {
|
|
301
350
|
console.log(" - editor setup skipped");
|
|
302
351
|
}
|