open-memex 0.4.1 → 0.5.0-alpha.4
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 +13 -7
- package/CONTRIBUTING.md +10 -10
- package/README.md +131 -16
- package/README.zh-CN.md +117 -15
- package/dist/cli.js +48 -9
- package/dist/init.js +515 -29
- package/docs/TEST-PLAN.md +2 -0
- package/docs/V2-DESIGN.md +61 -0
- package/package.json +1 -1
- package/scripts/smoke-pure.ts +104 -0
- package/src/cli.ts +50 -9
- package/src/init.ts +544 -27
package/docs/V2-DESIGN.md
CHANGED
|
@@ -882,6 +882,24 @@ requirement: personal data never touches third-party services). Benchmarks to tr
|
|
|
882
882
|
cannot confirm what the real run will do; and a destructive-path failure must
|
|
883
883
|
speak in user terms. Shipped as 0.4.1 hotfix on the stable line. Approved
|
|
884
884
|
2026-09-29.*
|
|
885
|
+
- **D45** — `init --global` (0.5.0-alpha.1): one-time user-level MCP wiring for
|
|
886
|
+
VS Code / Cursor. Writes the open-memex server entry to the editor's
|
|
887
|
+
user-level `mcp.json` (`%APPDATA%\Code\User\mcp.json` on Windows,
|
|
888
|
+
`~/Library/Application Support/Code/User/mcp.json` on macOS,
|
|
889
|
+
`~/.config/Code/User/mcp.json` on Linux; `~/.cursor/mcp.json` for Cursor)
|
|
890
|
+
instead of the project's `.vscode/mcp.json` — init once, the server starts
|
|
891
|
+
in every project. The entry keeps `cwd: "${workspaceFolder}"` so VS Code
|
|
892
|
+
substitutes it per window and project-scope resolution keeps working;
|
|
893
|
+
a per-project config still wins when present. Merge semantics are shared
|
|
894
|
+
with project-level init (merge, never clobber; `--force` overwrites).
|
|
895
|
+
Interactive `init` now asks per-project vs user-level for vscode/cursor
|
|
896
|
+
(default: per-project, preserving old behavior); `--global` skips the
|
|
897
|
+
question. For opencode, `--global` is a no-op that prints the native-plugin
|
|
898
|
+
one-liner (already global, and strictly more capable than plain-MCP mode);
|
|
899
|
+
Visual Studio stays solution-level by design. *Rationale: per-project init
|
|
900
|
+
is a paper cut that compounds — the data layer already needs zero per-project
|
|
901
|
+
setup (scope is derived from cwd), so the editor wiring should be able to
|
|
902
|
+
match. Approved 2026-09-29.*
|
|
885
903
|
- **D41** — The type taxonomy is reconciled to 11 types with one-line definitions
|
|
886
904
|
(§3.1): `fact` `preference` `decision` `constraint` `todo` `knowledge` `howto`
|
|
887
905
|
`gotcha` `lesson` `observation` `reference`. Merged away: `warning`→`gotcha`,
|
|
@@ -893,6 +911,49 @@ requirement: personal data never touches third-party services). Benchmarks to tr
|
|
|
893
911
|
is deliberately broader than `incident`: a postmortem's shape (timeline, root
|
|
894
912
|
cause, actions) is a template concern, not a type. Code
|
|
895
913
|
`MEMORY_TYPE_TAXONOMY` updated to match. Approved 2026-09-28.*
|
|
914
|
+
- **D46** — `init` with no `--client` auto-detects installed editors and wires
|
|
915
|
+
them all (0.5.0-alpha.2). Detection: VS Code via `code` on `PATH`, well-known
|
|
916
|
+
install locations, or an existing user-level `mcp.json`; Cursor via `cursor`
|
|
917
|
+
on `PATH` or `~/.cursor`; opencode via `opencode` on `PATH` or its global
|
|
918
|
+
config dir; Visual Studio only when the project has a `.sln` (solution-scoped
|
|
919
|
+
by design). Auto mode always wires user-level where the editor supports it —
|
|
920
|
+
VS Code / Cursor MCP entry (D45), and for opencode the native plugin entry is
|
|
921
|
+
now *actually merged* into `~/.config/opencode/opencode.json` (replacing D45's
|
|
922
|
+
hint-only `--global`), so one init covers every editor and every project.
|
|
923
|
+
A config file with comments (JSONC) is never rewritten — init prints the
|
|
924
|
+
manual one-liner instead. Interactive `init` shows the detected editors and
|
|
925
|
+
confirms wiring all of them (declining falls back to the single-editor
|
|
926
|
+
prompt); non-interactive (`--yes`) wires all detected with no prompts.
|
|
927
|
+
An explicit `--client` keeps the old single-editor behavior, including the
|
|
928
|
+
per-project default for vscode/cursor. *Rationale: Stone's two hats — he
|
|
929
|
+
writes code in several editors himself, and new users / pilot colleagues
|
|
930
|
+
should not have to learn `--client` to get started. The help text already
|
|
931
|
+
promised "default: auto-detect"; D46 makes the code keep that promise.
|
|
932
|
+
Approved 2026-09-29.*
|
|
933
|
+
- **D47** — when `init` refuses to touch a config file that isn't valid JSON
|
|
934
|
+
(usually JSONC with comments — VS Code / Cursor / opencode all accept them),
|
|
935
|
+
it now prints the exact snippet to add by hand: the section key plus the
|
|
936
|
+
`"open-memex"` entry, pretty-printed. Covers all three MCP-writing paths —
|
|
937
|
+
vscode/cursor (user + project level), opencode project-level `opencode.jsonc`,
|
|
938
|
+
and Visual Studio `.mcp.json` — matching the manual hint the opencode
|
|
939
|
+
`--global` plugin path already printed (D46). The file is still never
|
|
940
|
+
rewritten; the hint just makes "fix it manually" actionable. Triggered by
|
|
941
|
+
Stone's real Windows run: his user-level `mcp.json` had comments, init
|
|
942
|
+
correctly left it alone, but the old message gave him nothing to paste.
|
|
943
|
+
*Rationale: a refusal without a remedy is a dead end; the entry shape is
|
|
944
|
+
already computed, so printing it costs nothing. Approved 2026-09-29.*
|
|
945
|
+
- **D48** — new `open-memex uninstall` command, the reverse of `init`
|
|
946
|
+
(0.5.0-alpha.4). Removes the MCP server entry / opencode native plugin line /
|
|
947
|
+
Copilot instructions section that `init` wrote; memory data is never touched.
|
|
948
|
+
Client resolution mirrors `init` (explicit `--client`, else auto-detect with
|
|
949
|
+
an interactive confirm). Without `--global` it cleans both project-level and
|
|
950
|
+
user-level files — init may have written either, and a leftover entry at the
|
|
951
|
+
other level would be a surprise; `--global` restricts to user-level. Empty
|
|
952
|
+
sections/arrays are pruned; an instructions file that only held the
|
|
953
|
+
open-memex section is deleted. Non-JSON (JSONC) configs are left untouched
|
|
954
|
+
with the manual step, same D47 treatment as the init write path.
|
|
955
|
+
*Rationale: Stone asked "有 uninstall 吗" while testing init on Windows —
|
|
956
|
+
every write deserves an undo. Approved 2026-09-29.*
|
|
896
957
|
|
|
897
958
|
## Open Questions
|
|
898
959
|
|
package/package.json
CHANGED
package/scripts/smoke-pure.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { DEFAULT_CONFIG } from "../src/config.ts";
|
|
|
8
8
|
import { resolveProjectScope, resolveCwdScope, PERSONAL_SCOPE } from "../src/scope.ts";
|
|
9
9
|
import { cjkIndexText, cjkQueryExpr, hasCjk } from "../src/retrieve/cjk.ts";
|
|
10
10
|
import { contentHash, similarity, NEAR_DUP_THRESHOLD } from "../src/store/lifecycle.ts";
|
|
11
|
+
import { userMcpConfigPath, mergeServerEntry, detectInstalledClients, mergePluginEntry, opencodeGlobalConfigPath, printManualEntryHint, removeServerEntry, removePluginEntry, removeInstructionsSection } from "../src/init.ts";
|
|
11
12
|
|
|
12
13
|
let fails = 0;
|
|
13
14
|
function ok(name: string, cond: boolean, info?: unknown) {
|
|
@@ -376,5 +377,108 @@ const near = similarity(
|
|
|
376
377
|
ok(`similarity near-dup ${near.toFixed(2)} >= ${NEAR_DUP_THRESHOLD}`, near >= NEAR_DUP_THRESHOLD);
|
|
377
378
|
ok("similarity empty → 0", similarity("", "anything") === 0);
|
|
378
379
|
|
|
380
|
+
console.log("== init --global: userMcpConfigPath / mergeServerEntry ==");
|
|
381
|
+
// D45: user-level MCP config locations, per platform (platform param is injectable).
|
|
382
|
+
ok("vscode win32", userMcpConfigPath("vscode", "win32").endsWith(path.join("Code", "User", "mcp.json")));
|
|
383
|
+
ok("vscode darwin", userMcpConfigPath("vscode", "darwin").includes(path.join("Library", "Application Support", "Code", "User", "mcp.json")));
|
|
384
|
+
ok("vscode linux", userMcpConfigPath("vscode", "linux").endsWith(path.join(".config", "Code", "User", "mcp.json")));
|
|
385
|
+
ok("cursor is ~/.cursor/mcp.json on every platform",
|
|
386
|
+
(["win32", "darwin", "linux"] as const).every((p) =>
|
|
387
|
+
userMcpConfigPath("cursor", p).endsWith(path.join(".cursor", "mcp.json"))));
|
|
388
|
+
// mergeServerEntry: pure merge semantics.
|
|
389
|
+
const doc1: Record<string, unknown> = {};
|
|
390
|
+
ok("merge into empty doc adds", mergeServerEntry(doc1, "servers", { command: "x" }, false) === "added");
|
|
391
|
+
ok("entry landed under section", (doc1["servers"] as Record<string, unknown>)["open-memex"] !== undefined);
|
|
392
|
+
ok("existing entry kept without force", mergeServerEntry(doc1, "servers", { command: "y" }, false) === "kept");
|
|
393
|
+
ok("kept entry untouched", ((doc1["servers"] as Record<string, unknown>)["open-memex"] as Record<string, unknown>)["command"] === "x");
|
|
394
|
+
ok("force overwrites", mergeServerEntry(doc1, "servers", { command: "y" }, true) === "added");
|
|
395
|
+
ok("forced entry applied", ((doc1["servers"] as Record<string, unknown>)["open-memex"] as Record<string, unknown>)["command"] === "y");
|
|
396
|
+
const doc2: Record<string, unknown> = { servers: { other: { command: "z" } } };
|
|
397
|
+
ok("merge preserves sibling entries", mergeServerEntry(doc2, "servers", { command: "x" }, false) === "added"
|
|
398
|
+
&& (doc2["servers"] as Record<string, unknown>)["other"] !== undefined);
|
|
399
|
+
|
|
400
|
+
console.log("== init D46: auto-detect + opencode global plugin ==");
|
|
401
|
+
// opencodeGlobalConfigPath: user-level location, XDG-aware.
|
|
402
|
+
const fakeHome = fs.mkdtempSync(path.join(os.tmpdir(), "memex-smoke-"));
|
|
403
|
+
ok("opencode global config under ~/.config/opencode",
|
|
404
|
+
opencodeGlobalConfigPath(fakeHome).endsWith(path.join(".config", "opencode", "opencode.json")));
|
|
405
|
+
ok("opencode global config honors XDG_CONFIG_HOME", (() => {
|
|
406
|
+
const prev = process.env.XDG_CONFIG_HOME;
|
|
407
|
+
process.env.XDG_CONFIG_HOME = path.join(fakeHome, "xdg");
|
|
408
|
+
try {
|
|
409
|
+
return opencodeGlobalConfigPath(fakeHome).startsWith(path.join(fakeHome, "xdg"));
|
|
410
|
+
} finally {
|
|
411
|
+
if (prev === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
412
|
+
else process.env.XDG_CONFIG_HOME = prev;
|
|
413
|
+
}
|
|
414
|
+
})());
|
|
415
|
+
// mergePluginEntry: pure merge semantics.
|
|
416
|
+
const pdoc: Record<string, unknown> = {};
|
|
417
|
+
ok("plugin merge creates array", mergePluginEntry(pdoc, "file:///x", false) === "added"
|
|
418
|
+
&& JSON.stringify(pdoc["plugin"]) === JSON.stringify(["file:///x"]));
|
|
419
|
+
ok("plugin merge dup kept", mergePluginEntry(pdoc, "file:///x", false) === "kept");
|
|
420
|
+
ok("plugin merge force on dup adds nothing twice", mergePluginEntry(pdoc, "file:///x", true) === "added"
|
|
421
|
+
&& (pdoc["plugin"] as unknown[]).length === 1);
|
|
422
|
+
const pdoc2: Record<string, unknown> = { plugin: ["file:///other"], theme: "dark" };
|
|
423
|
+
ok("plugin merge preserves siblings", mergePluginEntry(pdoc2, "file:///x", false) === "added"
|
|
424
|
+
&& (pdoc2["plugin"] as unknown[]).length === 2 && pdoc2["theme"] === "dark");
|
|
425
|
+
// printManualEntryHint: the invalid-JSON bail-out must show the exact snippet to add by hand.
|
|
426
|
+
const hintLines: string[] = [];
|
|
427
|
+
const origErr = console.error;
|
|
428
|
+
console.error = (msg?: unknown) => { hintLines.push(String(msg)); };
|
|
429
|
+
printManualEntryHint("servers", { type: "stdio", command: "open-memex", args: ["mcp"] });
|
|
430
|
+
console.error = origErr;
|
|
431
|
+
const hintText = hintLines.join("\n");
|
|
432
|
+
ok("manual hint names the section", hintText.includes('"servers"'));
|
|
433
|
+
ok("manual hint contains the entry", hintText.includes('"open-memex"') && hintText.includes("stdio"));
|
|
434
|
+
// removeServerEntry: pure removal semantics.
|
|
435
|
+
const rdoc: Record<string, unknown> = { servers: { "open-memex": { command: "x" }, other: { command: "y" } }, untouched: 1 };
|
|
436
|
+
ok("remove deletes the entry", removeServerEntry(rdoc, "servers") === "removed"
|
|
437
|
+
&& !("open-memex" in (rdoc["servers"] as Record<string, unknown>))
|
|
438
|
+
&& "other" in (rdoc["servers"] as Record<string, unknown>));
|
|
439
|
+
ok("remove absent when entry already gone", removeServerEntry(rdoc, "servers") === "absent"
|
|
440
|
+
&& "servers" in rdoc); // sibling kept, section kept
|
|
441
|
+
const rdoc2: Record<string, unknown> = { servers: { "open-memex": { command: "x" } } };
|
|
442
|
+
ok("remove prunes empty section", removeServerEntry(rdoc2, "servers") === "removed" && !("servers" in rdoc2));
|
|
443
|
+
ok("remove absent when no entry", removeServerEntry({ servers: {} }, "servers") === "absent");
|
|
444
|
+
ok("remove absent when no section", removeServerEntry({}, "servers") === "absent");
|
|
445
|
+
// removePluginEntry: removes any open-memex URL, prunes empty array.
|
|
446
|
+
const rpdoc: Record<string, unknown> = { plugin: ["file:///x/open-memex/src/index.ts", "other-plugin"], theme: "dark" };
|
|
447
|
+
ok("plugin remove by substring", removePluginEntry(rpdoc, "open-memex") === "removed"
|
|
448
|
+
&& JSON.stringify(rpdoc["plugin"]) === JSON.stringify(["other-plugin"]));
|
|
449
|
+
const rpdoc3: Record<string, unknown> = { plugin: ["file:///open-memex/y"] };
|
|
450
|
+
ok("plugin remove prunes empty array", removePluginEntry(rpdoc3, "open-memex") === "removed" && !("plugin" in rpdoc3));
|
|
451
|
+
ok("plugin remove absent", removePluginEntry({ plugin: ["other"] }, "open-memex") === "absent");
|
|
452
|
+
// removeInstructionsSection: cuts MARKER..end, "" when nothing remains.
|
|
453
|
+
ok("instructions remove keeps prior content",
|
|
454
|
+
removeInstructionsSection("# mine\n\n<!-- open-memex -->\n# OpenMemex memory\n") === "# mine\n");
|
|
455
|
+
ok("instructions remove returns empty when wholesale",
|
|
456
|
+
removeInstructionsSection("<!-- open-memex -->\n# OpenMemex memory\n") === "");
|
|
457
|
+
ok("instructions remove no-op without marker",
|
|
458
|
+
removeInstructionsSection("# mine\n") === "# mine\n");
|
|
459
|
+
// detectInstalledClients with a fully fake env.
|
|
460
|
+
const binDir = fs.mkdtempSync(path.join(os.tmpdir(), "memex-bin-"));
|
|
461
|
+
fs.writeFileSync(path.join(binDir, "code"), "#!/bin/sh\n");
|
|
462
|
+
const detHome = fs.mkdtempSync(path.join(os.tmpdir(), "memex-home-"));
|
|
463
|
+
fs.mkdirSync(path.join(detHome, ".cursor"), { recursive: true });
|
|
464
|
+
fs.mkdirSync(path.join(detHome, ".config", "opencode"), { recursive: true });
|
|
465
|
+
const detRoot = fs.mkdtempSync(path.join(os.tmpdir(), "memex-root-"));
|
|
466
|
+
const detEnv = { pathEnv: binDir, home: detHome, platform: "linux" as const, root: detRoot, xdgConfigHome: path.join(detHome, ".config") };
|
|
467
|
+
const det = detectInstalledClients(detEnv);
|
|
468
|
+
ok("detects vscode via PATH", det.includes("vscode"));
|
|
469
|
+
ok("detects cursor via ~/.cursor", det.includes("cursor"));
|
|
470
|
+
ok("detects opencode via config dir", det.includes("opencode"));
|
|
471
|
+
ok("no visualstudio without .sln", !det.includes("visualstudio"));
|
|
472
|
+
fs.writeFileSync(path.join(detRoot, "app.sln"), "");
|
|
473
|
+
ok("visualstudio detected with .sln", detectInstalledClients(detEnv).includes("visualstudio"));
|
|
474
|
+
const emptyHome = fs.mkdtempSync(path.join(os.tmpdir(), "memex-empty-"));
|
|
475
|
+
const detEmpty = detectInstalledClients({ pathEnv: "", home: emptyHome, platform: "linux", root: emptyHome, xdgConfigHome: path.join(emptyHome, ".config") });
|
|
476
|
+
ok("empty env detects nothing", detEmpty.length === 0);
|
|
477
|
+
const winBin = fs.mkdtempSync(path.join(os.tmpdir(), "memex-winbin-"));
|
|
478
|
+
fs.writeFileSync(path.join(winBin, "code.cmd"), "@echo off\n");
|
|
479
|
+
ok("win32 detects vscode via code.cmd",
|
|
480
|
+
detectInstalledClients({ pathEnv: winBin, home: emptyHome, platform: "win32", root: emptyHome, xdgConfigHome: path.join(emptyHome, ".config") }).includes("vscode"));
|
|
481
|
+
for (const d of [fakeHome, binDir, detHome, detRoot, emptyHome, winBin]) fs.rmSync(d, { recursive: true, force: true });
|
|
482
|
+
|
|
379
483
|
console.log(fails === 0 ? "\nALL PASS" : `\n${fails} FAILURES`);
|
|
380
484
|
process.exit(fails === 0 ? 0 : 1);
|
package/src/cli.ts
CHANGED
|
@@ -279,18 +279,40 @@ Examples:
|
|
|
279
279
|
agent memory instructions. Existing files are merged, never clobbered.
|
|
280
280
|
|
|
281
281
|
Usage: open-memex init [--client vscode|cursor|opencode|visualstudio]
|
|
282
|
-
[--instructions personal|project] [--force] [--yes]
|
|
282
|
+
[--instructions personal|project] [--global] [--force] [--yes]
|
|
283
283
|
|
|
284
284
|
Flags:
|
|
285
|
-
--client editor to configure (default: auto-detect)
|
|
285
|
+
--client editor to configure (default: auto-detect all installed editors)
|
|
286
286
|
--instructions personal (default, ~/.copilot/copilot-instructions.md) or project
|
|
287
|
+
--global write the MCP server entry to the editor's user-level config
|
|
288
|
+
(VS Code / Cursor) — init once, works in every project.
|
|
289
|
+
For opencode, --global wires the native plugin at user level
|
|
290
|
+
(~/.config/opencode/opencode.json) — no per-project init needed.
|
|
287
291
|
--force overwrite existing config
|
|
288
292
|
--yes accept all defaults, never prompt
|
|
289
293
|
|
|
290
294
|
Examples:
|
|
291
295
|
open-memex init
|
|
296
|
+
open-memex init --client vscode --global --yes
|
|
292
297
|
open-memex init --client cursor --yes`,
|
|
293
298
|
|
|
299
|
+
uninstall: `Remove the editor wiring that \`init\` wrote: the MCP server entry,
|
|
300
|
+
the opencode native plugin line, and the Copilot instructions section.
|
|
301
|
+
Your memories are never touched.
|
|
302
|
+
|
|
303
|
+
Usage: open-memex uninstall [--client vscode|cursor|opencode|visualstudio]
|
|
304
|
+
[--global] [--yes]
|
|
305
|
+
|
|
306
|
+
Flags:
|
|
307
|
+
--client editor to unwire (default: auto-detect all installed editors)
|
|
308
|
+
--global only the user-level config; without it, both project-level and
|
|
309
|
+
user-level wiring are removed (init may have written either)
|
|
310
|
+
--yes accept all defaults, never prompt
|
|
311
|
+
|
|
312
|
+
Examples:
|
|
313
|
+
open-memex uninstall
|
|
314
|
+
open-memex uninstall --client vscode --yes`,
|
|
315
|
+
|
|
294
316
|
config: `Show config, or set a key.
|
|
295
317
|
|
|
296
318
|
Usage: open-memex config [set <key> <value>]
|
|
@@ -346,6 +368,8 @@ Usage:
|
|
|
346
368
|
open-memex mcp [--print-config vscode|cursor|claude|opencode|visualstudio]
|
|
347
369
|
open-memex init [--client vscode|cursor|opencode|visualstudio]
|
|
348
370
|
[--instructions personal|project] [--force] [--yes]
|
|
371
|
+
open-memex uninstall [--client vscode|cursor|opencode|visualstudio]
|
|
372
|
+
[--global] [--yes]
|
|
349
373
|
open-memex config [set <key> <value>]
|
|
350
374
|
open-memex capture --dry-run "text"
|
|
351
375
|
open-memex doctor
|
|
@@ -353,16 +377,19 @@ Usage:
|
|
|
353
377
|
Every command has its own help with description and examples:
|
|
354
378
|
open-memex <command> --help (or -h)
|
|
355
379
|
|
|
356
|
-
One-command project setup: \`open-memex init\` (or \`npx open-memex@alpha init\`)
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
380
|
+
One-command project setup: \`open-memex init\` (or \`npx open-memex@alpha init\`) detects
|
|
381
|
+
your installed editors and wires them all — user-level where the editor supports it
|
|
382
|
+
(VS Code / Cursor MCP config, opencode native plugin), so one init covers every project;
|
|
383
|
+
Visual Studio is included when the project has a solution file (its \`.mcp.json\`
|
|
384
|
+
stays solution-level by design). \`--client\` picks a single editor instead, and a
|
|
385
|
+
single-editor opencode init writes the per-project plain-MCP \`opencode.jsonc\`.
|
|
386
|
+
The Copilot memory instructions default to your user-level
|
|
360
387
|
\`~/.copilot/copilot-instructions.md\` (all projects, never checked into a repo);
|
|
361
388
|
\`--instructions project\` writes \`.github/copilot-instructions.md\` instead for
|
|
362
389
|
teams where everyone uses open-memex.
|
|
363
390
|
Existing files are merged, never clobbered; re-running is safe. On a terminal it
|
|
364
|
-
|
|
365
|
-
injection); \`--yes\` accepts all defaults, and non-terminal runs never prompt.
|
|
391
|
+
confirms the detected editors and asks a couple of settings (keyword capture,
|
|
392
|
+
first-turn injection); \`--yes\` accepts all defaults, and non-terminal runs never prompt.
|
|
366
393
|
\`open-memex config set <key> <value>\` changes those settings after install.
|
|
367
394
|
|
|
368
395
|
Once installed globally (\`npm i -g open-memex@alpha\`) the \`open-memex\` command is
|
|
@@ -595,7 +622,7 @@ async function main() {
|
|
|
595
622
|
}
|
|
596
623
|
|
|
597
624
|
// `init` is a pure file operation (§17 adoption path) — no DB needed.
|
|
598
|
-
// Interactive when on a TTY (
|
|
625
|
+
// Interactive when on a TTY (confirms detected editors + settings); --yes skips prompts.
|
|
599
626
|
if (cmd === "init") {
|
|
600
627
|
const flags = parseFlags(rest);
|
|
601
628
|
const { initProject } = await import("./init.ts");
|
|
@@ -604,6 +631,20 @@ async function main() {
|
|
|
604
631
|
force: flags["force"] === "true",
|
|
605
632
|
yes: flags["yes"] === "true",
|
|
606
633
|
instructions: flags["instructions"],
|
|
634
|
+
global: flags["global"] === "true",
|
|
635
|
+
});
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// `uninstall` reverses `init` — removes the editor wiring; never touches data.
|
|
640
|
+
// No DB needed (pure file operation, like init).
|
|
641
|
+
if (cmd === "uninstall") {
|
|
642
|
+
const flags = parseFlags(rest);
|
|
643
|
+
const { uninstallProject } = await import("./init.ts");
|
|
644
|
+
await uninstallProject({
|
|
645
|
+
client: flags["client"],
|
|
646
|
+
global: flags["global"] === "true",
|
|
647
|
+
yes: flags["yes"] === "true",
|
|
607
648
|
});
|
|
608
649
|
return;
|
|
609
650
|
}
|