open-memex 0.3.0-alpha.1 → 0.3.0-alpha.3

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
@@ -37,9 +37,11 @@ node --experimental-strip-types scripts\smoke-mcp.ts # MCP handshake + tool r
37
37
  After `npm i -g open-memex@alpha` (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 + .github/copilot-instructions.md;
42
- resolves the server command at init time — npx fallback when no durable bin is on PATH, D17),
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
@@ -77,7 +77,7 @@ open-memex init --client vscode
77
77
  npx -y open-memex@alpha init --client vscode
78
78
  ```
79
79
 
80
- Writes `.vscode/mcp.json` and `.github/copilot-instructions.md`, then reload the
80
+ Writes `.vscode/mcp.json` and user-level Copilot instructions, then reload the
81
81
  window and confirm the `open-memex` server is started in Copilot Chat's MCP panel.
82
82
 
83
83
  **Cursor:**
@@ -86,7 +86,7 @@ window and confirm the `open-memex` server is started in Copilot Chat's MCP pane
86
86
  open-memex init --client cursor
87
87
  ```
88
88
 
89
- Writes `.cursor/mcp.json` and `.github/copilot-instructions.md`.
89
+ Writes `.cursor/mcp.json` and user-level Copilot instructions.
90
90
 
91
91
  **opencode** (as a plain MCP consumer):
92
92
 
@@ -112,7 +112,7 @@ claude mcp add open-memex -- open-memex mcp
112
112
  open-memex init --client visualstudio
113
113
  ```
114
114
 
115
- Writes solution-level `.mcp.json` and `.github/copilot-instructions.md`. Requires
115
+ Writes solution-level `.mcp.json` and user-level Copilot instructions. Requires
116
116
  Visual Studio 2022 17.14+ or Visual Studio 2026 (**Windows-only**). Visual Studio
117
117
  also auto-discovers `.vscode/mcp.json` and `.cursor/mcp.json`, so the VS Code setup
118
118
  above works too.
@@ -123,6 +123,12 @@ above works too.
123
123
 
124
124
  `init` notes:
125
125
 
126
+ - The Copilot memory instructions default to **user-level**
127
+ (`~/.copilot/copilot-instructions.md`; `%USERPROFILE%\copilot-instructions.md`
128
+ for Visual Studio) — they apply to all your projects and are never checked
129
+ into a repo, so teammates without open-memex see nothing and nothing breaks
130
+ for them. `--instructions project` writes `.github/copilot-instructions.md`
131
+ instead, for teams where everyone uses open-memex.
126
132
  - On a terminal it interactively asks which editor to set up, whether to enable
127
133
  keyword auto-capture, and whether to inject memories on the first turn.
128
134
  `--yes` accepts the defaults; scripts / non-TTY never prompt (editor defaults to
@@ -237,6 +243,8 @@ open-memex config set <key> <value> # change a setting
237
243
  open-memex doctor # environment health check
238
244
  open-memex capture --dry-run "记住我喜欢简洁的回答" # preview keyword capture
239
245
  open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
246
+ open-memex --help # this reference
247
+ open-memex --version # installed version
240
248
  ```
241
249
 
242
250
  Memory operations:
@@ -280,7 +288,7 @@ server with cwd set to your project root (`init` handles this for you).
280
288
 
281
289
  > **Note:** MCP is request/response — it gives the agent tools, not the opencode
282
290
  > plugin's automatic keyword capture or first-turn context injection. Proactive
283
- > memory use depends on the agent's instructions (the `.github/copilot-instructions.md`
291
+ > memory use depends on the agent's instructions (the Copilot instructions
284
292
  > that `init` writes).
285
293
 
286
294
  ## Roadmap
package/README.zh-CN.md CHANGED
@@ -75,7 +75,7 @@ open-memex init --client vscode
75
75
  npx -y open-memex@alpha init --client vscode
76
76
  ```
77
77
 
78
- 自动写 `.vscode/mcp.json` 和 `.github/copilot-instructions.md`,然后重新加载窗口,
78
+ 自动写 `.vscode/mcp.json` 和用户级 Copilot instructions,然后重新加载窗口,
79
79
  在 Copilot Chat 的 MCP 面板里确认 `open-memex` server 已启动。
80
80
 
81
81
  **Cursor:**
@@ -84,7 +84,7 @@ npx -y open-memex@alpha init --client vscode
84
84
  open-memex init --client cursor
85
85
  ```
86
86
 
87
- 自动写 `.cursor/mcp.json` 和 `.github/copilot-instructions.md`。
87
+ 自动写 `.cursor/mcp.json` 和用户级 Copilot instructions。
88
88
 
89
89
  **opencode**(作为普通 MCP 客户端):
90
90
 
@@ -110,7 +110,7 @@ claude mcp add open-memex -- open-memex mcp
110
110
  open-memex init --client visualstudio
111
111
  ```
112
112
 
113
- 写 solution 级 `.mcp.json` 和 `.github/copilot-instructions.md`。需要
113
+ 写 solution 级 `.mcp.json` 和用户级 Copilot instructions。需要
114
114
  Visual Studio 2022 17.14+ 或 Visual Studio 2026(**仅 Windows**)。
115
115
  Visual Studio 也会自动发现 `.vscode/mcp.json` 和 `.cursor/mcp.json`,
116
116
  所以上面的 VS Code 配置同样可用。
@@ -120,6 +120,12 @@ Visual Studio 也会自动发现 `.vscode/mcp.json` 和 `.cursor/mcp.json`,
120
120
 
121
121
  `init` 说明:
122
122
 
123
+ - Copilot 记忆 instructions 默认写到**用户级**
124
+ (`~/.copilot/copilot-instructions.md`;Visual Studio 是
125
+ `%USERPROFILE%\copilot-instructions.md`)——所有项目生效,永不 checkin
126
+ 到 repo,没装 open-memex 的同事看不到、也不会出错。团队人人都用
127
+ open-memex 时可用 `--instructions project` 改写
128
+ `.github/copilot-instructions.md`。
123
129
  - 在终端里会交互式询问:配哪个编辑器、是否开启关键词自动捕获、
124
130
  是否在首轮注入记忆。`--yes` 全用默认值;脚本 / 非 TTY 环境不提问
125
131
  (编辑器默认 VS Code)。
@@ -236,6 +242,8 @@ open-memex config set <key> <value> # 改设置
236
242
  open-memex doctor # 环境健康检查
237
243
  open-memex capture --dry-run "记住我喜欢简洁的回答" # 预览关键词捕获
238
244
  open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
245
+ open-memex --help # 本帮助
246
+ open-memex --version # 已安装版本
239
247
  ```
240
248
 
241
249
  记忆操作:
@@ -280,7 +288,7 @@ project scope 从进程工作目录解析,所以配置 server 时 cwd 要指
280
288
 
281
289
  > **注意:** MCP 是请求/响应式的——它给 agent 提供 tools,但没有 opencode
282
290
  > 插件的关键词自动捕获和首轮上下文注入。想让 agent 主动用记忆,
283
- > 靠的是 agent 的 instructions(`init` 写的 `.github/copilot-instructions.md`)。
291
+ > 靠的是 agent 的 instructions(`init` 写的 Copilot instructions)。
284
292
 
285
293
  ## 路线图(Roadmap)
286
294
 
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
- function usage() {
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
- node --experimental-strip-types src/cli.ts where
21
- node --experimental-strip-types src/cli.ts list [--scope project|personal] [--type T] [--limit N]
22
- node --experimental-strip-types src/cli.ts search "query" [--scope project|personal|both] [--type T] [--limit N]
23
- node --experimental-strip-types src/cli.ts add "content" [--scope project|personal] [--type T] [--tag t1,t2]
24
- node --experimental-strip-types src/cli.ts supersede <id> "new content" [--type T] [--tag t1,t2]
25
- node --experimental-strip-types src/cli.ts status <id> active|deprecated|retracted|archived
26
- node --experimental-strip-types src/cli.ts forget <id>
27
- node --experimental-strip-types src/cli.ts reindex
28
- node --experimental-strip-types src/cli.ts scopes
29
- node --experimental-strip-types src/cli.ts migrate [--from <key>] [--to <key>]
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
- node --experimental-strip-types src/cli.ts migrate --to-v2 [--dry-run]
32
- node --experimental-strip-types src/cli.ts mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
33
- node --experimental-strip-types src/cli.ts init [--client vscode|cursor|opencode|visualstudio] [--force] [--yes]
34
- node --experimental-strip-types src/cli.ts config [set <key> <value>]
35
- node --experimental-strip-types src/cli.ts capture --dry-run "text"
36
- node --experimental-strip-types src/cli.ts doctor
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\`) plus
41
- \`.github/copilot-instructions.md\` — no copy-paste needed.
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(1);
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 dir = path.join(root, ".github");
179
- const file = path.join(dir, "copilot-instructions.md");
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(dir, { recursive: true });
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 记住… / remember… into memory?", DEFAULT_CONFIG.keywordCaptureEnabled);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-memex",
3
- "version": "0.3.0-alpha.1",
3
+ "version": "0.3.0-alpha.3",
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
@@ -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
- node --experimental-strip-types src/cli.ts where
29
- node --experimental-strip-types src/cli.ts list [--scope project|personal] [--type T] [--limit N]
30
- node --experimental-strip-types src/cli.ts search "query" [--scope project|personal|both] [--type T] [--limit N]
31
- node --experimental-strip-types src/cli.ts add "content" [--scope project|personal] [--type T] [--tag t1,t2]
32
- node --experimental-strip-types src/cli.ts supersede <id> "new content" [--type T] [--tag t1,t2]
33
- node --experimental-strip-types src/cli.ts status <id> active|deprecated|retracted|archived
34
- node --experimental-strip-types src/cli.ts forget <id>
35
- node --experimental-strip-types src/cli.ts reindex
36
- node --experimental-strip-types src/cli.ts scopes
37
- node --experimental-strip-types src/cli.ts migrate [--from <key>] [--to <key>]
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
- node --experimental-strip-types src/cli.ts migrate --to-v2 [--dry-run]
40
- node --experimental-strip-types src/cli.ts mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
41
- node --experimental-strip-types src/cli.ts init [--client vscode|cursor|opencode|visualstudio] [--force] [--yes]
42
- node --experimental-strip-types src/cli.ts config [set <key> <value>]
43
- node --experimental-strip-types src/cli.ts capture --dry-run "text"
44
- node --experimental-strip-types src/cli.ts doctor
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\`) plus
49
- \`.github/copilot-instructions.md\` — no copy-paste needed.
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(1);
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(root: string): string {
190
- const dir = path.join(root, ".github");
191
- const file = path.join(dir, "copilot-instructions.md");
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(dir, { recursive: true });
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 记住… / remember… into memory?",
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
- if (client !== "opencode") writeInstructions(root);
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
  }