@llmnesia/mcp 0.1.10 → 0.1.12

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/README.md CHANGED
@@ -55,6 +55,13 @@ The installer:
55
55
  of those standard config paths, so an app installed later does not require
56
56
  running setup again.
57
57
 
58
+ On Windows, Claude Desktop uses its supported packaged-extension flow instead
59
+ of the legacy JSON config. If Claude is installed, its normal LLMnesia install
60
+ window opens during setup; click **Install** once. Claude can run that extension
61
+ with its built-in Node.js, while the system Node installation continues to run
62
+ the browser helper and other desktop AI integrations. If Claude is installed
63
+ later, run the same LLMnesia setup command once more.
64
+
58
65
  The `install` command is the approval to perform those setup steps. It does not
59
66
  interrupt setup with a separate prompt for every detected app, and it never
60
67
  prints existing client configurations or their credentials.
@@ -121,7 +128,7 @@ received data — check it before concluding a chat does not exist.
121
128
  | Client | How `install` wires it |
122
129
  | --- | --- |
123
130
  | Claude Code | Runs `claude mcp add --scope user` with the absolute Node and installed runtime paths when available. Otherwise it writes the documented user-scope `~/.claude.json` entry, so Windows users do not need the `claude` command on PATH. |
124
- | Claude Desktop | Edits `claude_desktop_config.json` at the standard OS-specific path, preparing it in advance if Claude Desktop is installed later. |
131
+ | Claude Desktop | Windows opens Claude's regular packaged-extension installer and removes obsolete LLMnesia JSON entries. macOS keeps the working local JSON registration. |
125
132
  | Cursor | Edits `~/.cursor/mcp.json`, preparing it in advance if Cursor is installed later. |
126
133
  | Codex / ChatGPT desktop | Runs `codex mcp add` with the absolute runtime paths when available. If the bundled CLI is unavailable, the installer safely edits `~/.codex/config.toml` itself and backs up existing settings first, including preparing it for a later installation. Read-only LLMnesia tools are configured to run without repeated approval prompts; writes still ask. |
127
134
  | Others (Windsurf, Zed, LM Studio, …) | Prints the generic stdio block for you to paste. |
@@ -38,7 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  ));
39
39
 
40
40
  // src/version.ts
41
- var VERSION = true ? "0.1.10" : "0.0.0-dev";
41
+ var VERSION = true ? "0.1.12" : "0.0.0-dev";
42
42
 
43
43
  export {
44
44
  __require,
@@ -15,7 +15,7 @@ import {
15
15
  __commonJS,
16
16
  __require,
17
17
  __toESM
18
- } from "./chunk-LA3BU5ZR.js";
18
+ } from "./chunk-MI5RBP7Y.js";
19
19
 
20
20
  // ../node_modules/isexe/windows.js
21
21
  var require_windows = __commonJS({
@@ -41,15 +41,15 @@ var require_windows = __commonJS({
41
41
  }
42
42
  return false;
43
43
  }
44
- function checkStat(stat6, path, options) {
45
- if (!stat6.isSymbolicLink() && !stat6.isFile()) {
44
+ function checkStat(stat7, path, options) {
45
+ if (!stat7.isSymbolicLink() && !stat7.isFile()) {
46
46
  return false;
47
47
  }
48
48
  return checkPathExt(path, options);
49
49
  }
50
50
  function isexe(path, options, cb) {
51
- fs.stat(path, function(er, stat6) {
52
- cb(er, er ? false : checkStat(stat6, path, options));
51
+ fs.stat(path, function(er, stat7) {
52
+ cb(er, er ? false : checkStat(stat7, path, options));
53
53
  });
54
54
  }
55
55
  function sync(path, options) {
@@ -66,20 +66,20 @@ var require_mode = __commonJS({
66
66
  isexe.sync = sync;
67
67
  var fs = __require("fs");
68
68
  function isexe(path, options, cb) {
69
- fs.stat(path, function(er, stat6) {
70
- cb(er, er ? false : checkStat(stat6, options));
69
+ fs.stat(path, function(er, stat7) {
70
+ cb(er, er ? false : checkStat(stat7, options));
71
71
  });
72
72
  }
73
73
  function sync(path, options) {
74
74
  return checkStat(fs.statSync(path), options);
75
75
  }
76
- function checkStat(stat6, options) {
77
- return stat6.isFile() && checkMode(stat6, options);
76
+ function checkStat(stat7, options) {
77
+ return stat7.isFile() && checkMode(stat7, options);
78
78
  }
79
- function checkMode(stat6, options) {
80
- var mod = stat6.mode;
81
- var uid = stat6.uid;
82
- var gid = stat6.gid;
79
+ function checkMode(stat7, options) {
80
+ var mod = stat7.mode;
81
+ var uid = stat7.uid;
82
+ var gid = stat7.gid;
83
83
  var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
84
84
  var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
85
85
  var u = parseInt("100", 8);
@@ -251,8 +251,8 @@ var require_path_key = __commonJS({
251
251
  "use strict";
252
252
  var pathKey = (options = {}) => {
253
253
  const environment = options.env || process.env;
254
- const platform4 = options.platform || process.platform;
255
- if (platform4 !== "win32") {
254
+ const platform5 = options.platform || process.platform;
255
+ if (platform5 !== "win32") {
256
256
  return "PATH";
257
257
  }
258
258
  return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
@@ -2439,8 +2439,8 @@ var FSWatcher = class extends EventEmitter {
2439
2439
  }
2440
2440
  return this._userIgnored(path, stats);
2441
2441
  }
2442
- _isntIgnored(path, stat6) {
2443
- return !this._isIgnored(path, stat6);
2442
+ _isntIgnored(path, stat7) {
2443
+ return !this._isIgnored(path, stat7);
2444
2444
  }
2445
2445
  /**
2446
2446
  * Provides a set of common helpers and properties relating to symlink handling.
@@ -3258,12 +3258,23 @@ async function registerClients(options) {
3258
3258
  )
3259
3259
  );
3260
3260
  if (claudeDesktop) {
3261
- results.push(
3262
- await safe(
3263
- "Claude Desktop",
3264
- () => registerJsonClient("Claude Desktop", claudeDesktop, options.serve, options.confirm, now, prepareMissing, false, false)
3265
- )
3266
- );
3261
+ if (osPlatform2 === "win32") {
3262
+ const cleanup = await safe("Claude Desktop", () => unregisterJsonClient("Claude Desktop", claudeDesktop, now));
3263
+ results.push(
3264
+ cleanup.action === "error" ? cleanup : {
3265
+ client: "Claude Desktop",
3266
+ action: "skipped",
3267
+ detail: "Claude Desktop uses the packaged LLMnesia extension on Windows."
3268
+ }
3269
+ );
3270
+ } else {
3271
+ results.push(
3272
+ await safe(
3273
+ "Claude Desktop",
3274
+ () => registerJsonClient("Claude Desktop", claudeDesktop, options.serve, options.confirm, now, prepareMissing, false, false)
3275
+ )
3276
+ );
3277
+ }
3267
3278
  }
3268
3279
  results.push(
3269
3280
  await safe("Cursor", () => registerJsonClient("Cursor", cursor, options.serve, options.confirm, now, prepareMissing))
@@ -3777,6 +3788,36 @@ function formatDoctorReport(report) {
3777
3788
  return report.checks.map((c) => `${icon[c.status]} ${c.name}: ${c.detail}`).join("\n");
3778
3789
  }
3779
3790
 
3791
+ // src/claudeDesktopExtension.ts
3792
+ import { execFile as execFile3 } from "child_process";
3793
+ import { access as access2, stat as stat6 } from "fs/promises";
3794
+ import { homedir as homedir5, platform as platform4 } from "os";
3795
+ import { join as join7 } from "path";
3796
+ import { promisify as promisify3 } from "util";
3797
+ var execFileAsync3 = promisify3(execFile3);
3798
+ async function defaultOpenBundle(bundlePath) {
3799
+ await execFileAsync3("rundll32.exe", ["url.dll,FileProtocolHandler", bundlePath], { windowsHide: true });
3800
+ }
3801
+ async function promptClaudeDesktopExtension(options) {
3802
+ const home2 = options.home ?? homedir5();
3803
+ const osPlatform2 = options.osPlatform ?? platform4();
3804
+ const bundlePath = join7(options.binDir, "llmnesia.mcpb");
3805
+ if (osPlatform2 !== "win32") {
3806
+ return { status: "unsupported", bundlePath };
3807
+ }
3808
+ const appData = options.appData ?? process.env.APPDATA ?? join7(home2, "AppData", "Roaming");
3809
+ try {
3810
+ if (!(await stat6(join7(appData, "Claude"))).isDirectory()) {
3811
+ return { status: "not-installed", bundlePath };
3812
+ }
3813
+ } catch {
3814
+ return { status: "not-installed", bundlePath };
3815
+ }
3816
+ await access2(bundlePath);
3817
+ await (options.openBundle ?? defaultOpenBundle)(bundlePath);
3818
+ return { status: "opened", bundlePath };
3819
+ }
3820
+
3780
3821
  // src/cli.ts
3781
3822
  var USAGE = `llmnesia-mcp ${VERSION}
3782
3823
 
@@ -3888,6 +3929,19 @@ async function runInstall(positionals, options, flags) {
3888
3929
  `);
3889
3930
  }
3890
3931
  hadProblems ||= registrations.errors.length > 0;
3932
+ if (process.platform === "win32") {
3933
+ try {
3934
+ const claude = await promptClaudeDesktopExtension({ binDir: runtime.binDir });
3935
+ if (claude.status === "opened") {
3936
+ process.stdout.write("Claude opened. Click Install to add LLMnesia.\n");
3937
+ }
3938
+ } catch (err) {
3939
+ process.stderr.write(
3940
+ `Claude Desktop needs one more step: open ${runtime.binDir}\\llmnesia.mcpb and click Install. (${err instanceof Error ? err.message : String(err)})
3941
+ `
3942
+ );
3943
+ }
3944
+ }
3891
3945
  if (hadProblems) {
3892
3946
  process.stderr.write("\nSetup needs attention. Fix the message above, then run the same command again.\n");
3893
3947
  return 1;
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire as __llmnesiaCreateRequire } from "node:module";
3
3
  const require = __llmnesiaCreateRequire(import.meta.url);
4
4
  import {
5
5
  VERSION
6
- } from "./chunk-LA3BU5ZR.js";
6
+ } from "./chunk-MI5RBP7Y.js";
7
7
 
8
8
  // src/nodeDownload.ts
9
9
  var NODE_DOWNLOAD_URLS = {
@@ -141,7 +141,7 @@ async function bootstrap() {
141
141
  await guideUnsupportedNodeVersion(process.versions.node);
142
142
  return 1;
143
143
  }
144
- const { main } = await import("./cli-VUTW2WGY.js");
144
+ const { main } = await import("./cli-GKHVUCEP.js");
145
145
  return main();
146
146
  }
147
147
  bootstrap().then((code) => {
Binary file
package/dist/mcp.js CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  __commonJS,
14
14
  __export,
15
15
  __toESM
16
- } from "./chunk-LA3BU5ZR.js";
16
+ } from "./chunk-MI5RBP7Y.js";
17
17
 
18
18
  // ../node_modules/ajv/dist/compile/codegen/code.js
19
19
  var require_code = __commonJS({
@@ -3211,8 +3211,8 @@ var require_utils = __commonJS({
3211
3211
  }
3212
3212
  return ind;
3213
3213
  }
3214
- function removeDotSegments(path) {
3215
- let input = path;
3214
+ function removeDotSegments(path2) {
3215
+ let input = path2;
3216
3216
  const output = [];
3217
3217
  let nextSlash = -1;
3218
3218
  let len = 0;
@@ -3464,8 +3464,8 @@ var require_schemes = __commonJS({
3464
3464
  wsComponent.secure = void 0;
3465
3465
  }
3466
3466
  if (wsComponent.resourceName) {
3467
- const [path, query] = wsComponent.resourceName.split("?");
3468
- wsComponent.path = path && path !== "/" ? path : void 0;
3467
+ const [path2, query] = wsComponent.resourceName.split("?");
3468
+ wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
3469
3469
  wsComponent.query = query;
3470
3470
  wsComponent.resourceName = void 0;
3471
3471
  }
@@ -7375,8 +7375,8 @@ function getErrorMap() {
7375
7375
 
7376
7376
  // ../node_modules/zod/v3/helpers/parseUtil.js
7377
7377
  var makeIssue = (params) => {
7378
- const { data, path, errorMaps, issueData } = params;
7379
- const fullPath = [...path, ...issueData.path || []];
7378
+ const { data, path: path2, errorMaps, issueData } = params;
7379
+ const fullPath = [...path2, ...issueData.path || []];
7380
7380
  const fullIssue = {
7381
7381
  ...issueData,
7382
7382
  path: fullPath
@@ -7492,11 +7492,11 @@ var errorUtil;
7492
7492
 
7493
7493
  // ../node_modules/zod/v3/types.js
7494
7494
  var ParseInputLazyPath = class {
7495
- constructor(parent, value, path, key) {
7495
+ constructor(parent, value, path2, key) {
7496
7496
  this._cachedPath = [];
7497
7497
  this.parent = parent;
7498
7498
  this.data = value;
7499
- this._path = path;
7499
+ this._path = path2;
7500
7500
  this._key = key;
7501
7501
  }
7502
7502
  get path() {
@@ -11133,10 +11133,10 @@ function assignProp(target, prop, value) {
11133
11133
  configurable: true
11134
11134
  });
11135
11135
  }
11136
- function getElementAtPath(obj, path) {
11137
- if (!path)
11136
+ function getElementAtPath(obj, path2) {
11137
+ if (!path2)
11138
11138
  return obj;
11139
- return path.reduce((acc, key) => acc?.[key], obj);
11139
+ return path2.reduce((acc, key) => acc?.[key], obj);
11140
11140
  }
11141
11141
  function promiseAllObject(promisesObj) {
11142
11142
  const keys = Object.keys(promisesObj);
@@ -11456,11 +11456,11 @@ function aborted(x, startIndex = 0) {
11456
11456
  }
11457
11457
  return false;
11458
11458
  }
11459
- function prefixIssues(path, issues) {
11459
+ function prefixIssues(path2, issues) {
11460
11460
  return issues.map((iss) => {
11461
11461
  var _a;
11462
11462
  (_a = iss).path ?? (_a.path = []);
11463
- iss.path.unshift(path);
11463
+ iss.path.unshift(path2);
11464
11464
  return iss;
11465
11465
  });
11466
11466
  }
@@ -14871,11 +14871,11 @@ function normalizeObjectSchema(schema) {
14871
14871
  }
14872
14872
  return void 0;
14873
14873
  }
14874
- function getDotPath(path) {
14875
- if (path.length === 0) {
14874
+ function getDotPath(path2) {
14875
+ if (path2.length === 0) {
14876
14876
  return "object root";
14877
14877
  }
14878
- return path.reduce((acc, seg, index) => {
14878
+ return path2.reduce((acc, seg, index) => {
14879
14879
  if (index === 0) {
14880
14880
  return String(seg);
14881
14881
  }
@@ -21131,6 +21131,11 @@ var StdioServerTransport = class {
21131
21131
  }
21132
21132
  };
21133
21133
 
21134
+ // src/mcp.ts
21135
+ import { realpathSync } from "fs";
21136
+ import { fileURLToPath } from "url";
21137
+ import path from "path";
21138
+
21134
21139
  // src/saveSchema.ts
21135
21140
  import { createHash } from "crypto";
21136
21141
  var saveMessageSchema = external_exports.object({
@@ -21360,6 +21365,51 @@ var CompanionService = class _CompanionService {
21360
21365
  function noop() {
21361
21366
  }
21362
21367
 
21368
+ // src/lazyResource.ts
21369
+ var ResourcePreparingError = class extends Error {
21370
+ constructor() {
21371
+ super("Resource is still preparing");
21372
+ this.name = "ResourcePreparingError";
21373
+ }
21374
+ };
21375
+ var LazyResource = class {
21376
+ constructor(open) {
21377
+ this.open = open;
21378
+ }
21379
+ open;
21380
+ resource = null;
21381
+ failure;
21382
+ completion = null;
21383
+ start() {
21384
+ if (this.completion) return;
21385
+ this.completion = Promise.resolve().then(() => this.open()).then(
21386
+ (resource) => {
21387
+ this.resource = resource;
21388
+ },
21389
+ (error2) => {
21390
+ this.failure = error2;
21391
+ }
21392
+ );
21393
+ }
21394
+ async get(waitMs) {
21395
+ this.start();
21396
+ if (this.resource) return this.resource;
21397
+ let timeout;
21398
+ await Promise.race([
21399
+ this.completion,
21400
+ new Promise((resolve) => {
21401
+ timeout = setTimeout(resolve, waitMs);
21402
+ })
21403
+ ]);
21404
+ if (timeout) clearTimeout(timeout);
21405
+ if (this.resource) return this.resource;
21406
+ if (this.failure) {
21407
+ throw this.failure;
21408
+ }
21409
+ throw new ResourcePreparingError();
21410
+ }
21411
+ };
21412
+
21363
21413
  // src/mcp.ts
21364
21414
  function jsonResult(payload) {
21365
21415
  return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] };
@@ -21387,13 +21437,25 @@ function parseDate(value) {
21387
21437
  }
21388
21438
  async function runServe() {
21389
21439
  const root = resolveCorpusDir(process.env.LLMNESIA_CORPUS_DIR);
21390
- const service = await CompanionService.open(root, {
21391
- // stdout is the MCP JSON-RPC channel, so diagnostics go to stderr.
21392
- onDrainError: (error2) => process.stderr.write(
21393
- `llmnesia: inbox drain failed, serving the existing index: ${error2 instanceof Error ? error2.message : String(error2)}
21440
+ const service = new LazyResource(
21441
+ () => CompanionService.open(root, {
21442
+ // stdout is the MCP JSON-RPC channel, so diagnostics go to stderr.
21443
+ onDrainError: (error2) => process.stderr.write(
21444
+ `llmnesia: inbox drain failed, serving the existing index: ${error2 instanceof Error ? error2.message : String(error2)}
21394
21445
  `
21395
- )
21396
- });
21446
+ )
21447
+ })
21448
+ );
21449
+ const withService = async (operation) => {
21450
+ try {
21451
+ return await operation(await service.get(5e3));
21452
+ } catch (err) {
21453
+ if (err instanceof ResourcePreparingError) {
21454
+ return errorResult("LLMnesia is still preparing the local conversation index. Retry this tool shortly.");
21455
+ }
21456
+ return errorResult(`LLMnesia could not open the local conversation index: ${err instanceof Error ? err.message : String(err)}`);
21457
+ }
21458
+ };
21397
21459
  const server = new McpServer(
21398
21460
  { name: "llmnesia", version: VERSION },
21399
21461
  {
@@ -21423,7 +21485,7 @@ async function runServe() {
21423
21485
  openWorldHint: false
21424
21486
  }
21425
21487
  },
21426
- async (args) => {
21488
+ async (args) => withService(async (service2) => {
21427
21489
  const filters = {
21428
21490
  platform: args.platform,
21429
21491
  title: args.title,
@@ -21432,8 +21494,8 @@ async function runServe() {
21432
21494
  limit: args.limit,
21433
21495
  matchMode: args.match_mode
21434
21496
  };
21435
- const hits = await service.search(args.query, filters);
21436
- const status = await service.corpusStatus({ refresh: false });
21497
+ const hits = await service2.search(args.query, filters);
21498
+ const status = await service2.corpusStatus({ refresh: false });
21437
21499
  return jsonResult({
21438
21500
  count: hits.length,
21439
21501
  corpus: corpusField(status),
@@ -21450,7 +21512,7 @@ async function runServe() {
21450
21512
  messageCount: h.messageCount
21451
21513
  }))
21452
21514
  });
21453
- }
21515
+ })
21454
21516
  );
21455
21517
  server.registerTool(
21456
21518
  "get_conversation",
@@ -21467,8 +21529,8 @@ async function runServe() {
21467
21529
  openWorldHint: false
21468
21530
  }
21469
21531
  },
21470
- async (args) => {
21471
- const record2 = await service.getConversation(args.id);
21532
+ async (args) => withService(async (service2) => {
21533
+ const record2 = await service2.getConversation(args.id);
21472
21534
  if (!record2) {
21473
21535
  return errorResult(`No conversation found with id '${args.id}'.`);
21474
21536
  }
@@ -21481,7 +21543,7 @@ async function runServe() {
21481
21543
  text: m.formattedText ?? m.text
21482
21544
  }))
21483
21545
  });
21484
- }
21546
+ })
21485
21547
  );
21486
21548
  server.registerTool(
21487
21549
  "list_recent",
@@ -21498,9 +21560,9 @@ async function runServe() {
21498
21560
  openWorldHint: false
21499
21561
  }
21500
21562
  },
21501
- async (args) => {
21502
- const entries = await service.listRecent(args.limit ?? 10);
21503
- const status = await service.corpusStatus({ refresh: false });
21563
+ async (args) => withService(async (service2) => {
21564
+ const entries = await service2.listRecent(args.limit ?? 10);
21565
+ const status = await service2.corpusStatus({ refresh: false });
21504
21566
  return jsonResult({
21505
21567
  count: entries.length,
21506
21568
  corpus: corpusField(status),
@@ -21514,7 +21576,7 @@ async function runServe() {
21514
21576
  summary: e.summary ?? e.preview
21515
21577
  }))
21516
21578
  });
21517
- }
21579
+ })
21518
21580
  );
21519
21581
  server.registerTool(
21520
21582
  "list_conversations",
@@ -21532,9 +21594,9 @@ async function runServe() {
21532
21594
  openWorldHint: false
21533
21595
  }
21534
21596
  },
21535
- async (args) => {
21536
- const entries = await service.listConversations(args.limit ?? 10, args.sort ?? "recent");
21537
- const status = await service.corpusStatus({ refresh: false });
21597
+ async (args) => withService(async (service2) => {
21598
+ const entries = await service2.listConversations(args.limit ?? 10, args.sort ?? "recent");
21599
+ const status = await service2.corpusStatus({ refresh: false });
21538
21600
  return jsonResult({
21539
21601
  count: entries.length,
21540
21602
  sort: args.sort ?? "recent",
@@ -21550,7 +21612,7 @@ async function runServe() {
21550
21612
  summary: e.summary ?? e.preview
21551
21613
  }))
21552
21614
  });
21553
- }
21615
+ })
21554
21616
  );
21555
21617
  server.registerTool(
21556
21618
  "corpus_status",
@@ -21565,10 +21627,10 @@ async function runServe() {
21565
21627
  openWorldHint: false
21566
21628
  }
21567
21629
  },
21568
- async () => {
21569
- const status = await service.corpusStatus();
21630
+ async () => withService(async (service2) => {
21631
+ const status = await service2.corpusStatus();
21570
21632
  return jsonResult(status);
21571
- }
21633
+ })
21572
21634
  );
21573
21635
  server.registerTool(
21574
21636
  "save_conversation",
@@ -21583,21 +21645,29 @@ async function runServe() {
21583
21645
  openWorldHint: false
21584
21646
  }
21585
21647
  },
21586
- async (args) => {
21648
+ async (args) => withService(async (service2) => {
21587
21649
  try {
21588
- const result = await service.saveConversation(args);
21650
+ const result = await service2.saveConversation(args);
21589
21651
  return jsonResult(result);
21590
21652
  } catch (err) {
21591
21653
  return errorResult(`save_conversation failed: ${err instanceof Error ? err.message : String(err)}`);
21592
21654
  }
21593
- }
21655
+ })
21594
21656
  );
21657
+ server.server.oninitialized = () => service.start();
21595
21658
  const transport = new StdioServerTransport();
21596
21659
  await server.connect(transport);
21597
- process.stderr.write(`llmnesia MCP server ready (corpus: ${root})
21660
+ process.stderr.write(`llmnesia MCP protocol ready; waiting for client initialization (${root})
21598
21661
  `);
21599
21662
  }
21600
- var isMain = import.meta.url === `file://${process.argv[1]}`;
21663
+ var isMain = (() => {
21664
+ if (!process.argv[1]) return false;
21665
+ try {
21666
+ return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1]);
21667
+ } catch {
21668
+ return path.resolve(fileURLToPath(import.meta.url)) === path.resolve(process.argv[1]);
21669
+ }
21670
+ })();
21601
21671
  if (isMain) {
21602
21672
  runServe().catch((err) => {
21603
21673
  process.stderr.write(`Fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnesia/mcp",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "comment:mcpName": "The MCP Registry's ownership marker: it must equal server.json's `name`, and the namespace must match how you authenticate with mcp-publisher. `com.llmnesia/...` requires DNS auth (a TXT record on llmnesia.com) — see docs/MCP_INSTALLER_BOARD.md.",
@@ -39,12 +39,14 @@
39
39
  "access": "public"
40
40
  },
41
41
  "scripts": {
42
- "build": "tsup",
42
+ "build": "tsup && npm run build:mcpb",
43
+ "build:mcpb": "node scripts/build-mcpb.mjs",
43
44
  "prepack": "npm run build",
44
45
  "dev": "tsx src/cli.ts",
45
46
  "mcp": "tsx src/mcp.ts",
46
47
  "typecheck": "tsc --noEmit",
47
- "test": "vitest run"
48
+ "test": "vitest run",
49
+ "test:mcpb": "node scripts/smoke-mcpb.mjs"
48
50
  },
49
51
  "comment:deps": "This package publishes with ZERO runtime dependencies — everything is bundled into dist by tsup (see noExternal in tsup.config.ts). That is not just an optimisation: `install` copies dist/ to ~/.llmnesia/bin so MCP clients can spawn it by absolute path, and nothing puts a node_modules beside that copy, so any unbundled import would fail there with ERR_MODULE_NOT_FOUND. Listing them as runtime deps would also be false comfort — npm would install them next to the package, not next to the copy that actually runs. The workspace packages additionally must not appear in the install graph at all: shared-types does not exist on the registry, and the published claude-code-host is an older build without the exports this package needs.",
50
52
  "devDependencies": {
@@ -52,6 +54,7 @@
52
54
  "@llmnesia/shared-types": "*",
53
55
  "@modelcontextprotocol/sdk": "^1.29.0",
54
56
  "@types/node": "^22.13.0",
57
+ "adm-zip": "^0.5.18",
55
58
  "chokidar": "^4.0.3",
56
59
  "cross-spawn": "^7.0.6",
57
60
  "fast-uri": "^3.1.5",
package/server.json CHANGED
@@ -3,13 +3,13 @@
3
3
  "name": "com.llmnesia/mcp",
4
4
  "title": "LLMnesia",
5
5
  "description": "Search your AI chat history from Claude, Cursor, Codex, and other MCP clients.",
6
- "version": "0.1.3",
6
+ "version": "0.1.12",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "registryBaseUrl": "https://registry.npmjs.org",
11
11
  "identifier": "@llmnesia/mcp",
12
- "version": "0.1.3",
12
+ "version": "0.1.12",
13
13
  "transport": {
14
14
  "type": "stdio"
15
15
  }