open-memex 0.3.0-alpha → 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/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
  }
@@ -0,0 +1 @@
1
+ {"compilerOptions":{"declaration":false,"noEmit":false,"outDir":"dist","rewriteRelativeImportExtensions":true,"sourceMap":false},"extends":"./tsconfig.json","include":["src/**/*.ts"]}
package/bin/open-memex.js DELETED
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env node
2
- // `open-memex` bin launcher: re-execs src/cli.ts with TypeScript type-stripping
3
- // enabled, so the command works on Node 22.6+ without the user passing
4
- // --experimental-strip-types themselves. (Plain JS — no build step.)
5
- import { spawn } from "node:child_process";
6
- import path from "node:path";
7
- import { fileURLToPath } from "node:url";
8
-
9
- const entry = path.join(
10
- path.dirname(fileURLToPath(import.meta.url)),
11
- "..",
12
- "src",
13
- "cli.ts",
14
- );
15
-
16
- const child = spawn(
17
- process.execPath,
18
- ["--experimental-strip-types", entry, ...process.argv.slice(2)],
19
- { stdio: "inherit" },
20
- );
21
- child.on("error", (err) => {
22
- console.error(`open-memex: failed to start: ${err.message}`);
23
- process.exit(1);
24
- });
25
- child.on("exit", (code, signal) => {
26
- if (signal) process.kill(process.pid, signal);
27
- else process.exit(code ?? 0);
28
- });