@llmnesia/mcp 0.2.9 → 0.2.10

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.
@@ -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.2.9" : "0.0.0-dev";
41
+ var VERSION = true ? "0.2.10" : "0.0.0-dev";
42
42
 
43
43
  export {
44
44
  __require,
@@ -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-YT6GNKKG.js";
6
+ } from "./chunk-GLCLSBT6.js";
7
7
 
8
8
  // src/config.ts
9
9
  import { readFileSync } from "fs";
@@ -47,7 +47,7 @@ function expandHome(p) {
47
47
  import { join as join2 } from "path";
48
48
  import { readdir } from "fs/promises";
49
49
  import { createHash } from "crypto";
50
- var INDEX_FORMAT_VERSION = 5;
50
+ var INDEX_FORMAT_VERSION = 7;
51
51
  function indexDbFilename(version) {
52
52
  return version === 1 ? "llmnesia.db" : `llmnesia-v${version}.db`;
53
53
  }
@@ -217,6 +217,13 @@ function canonicalConversationDoc(c) {
217
217
  observedAt: c.providerProject.observedAt
218
218
  };
219
219
  }
220
+ if (c.providerWorkspace) {
221
+ out.providerWorkspace = {
222
+ workspaceId: c.providerWorkspace.workspaceId,
223
+ source: c.providerWorkspace.source,
224
+ observedAt: c.providerWorkspace.observedAt
225
+ };
226
+ }
220
227
  if (c.models && c.models.length > 0) out.models = [...c.models];
221
228
  assignIfDefined(out, "modelMetadataUpdatedAt", c.modelMetadataUpdatedAt);
222
229
  if (c.summary) {
@@ -721,6 +728,17 @@ var EMPTY_REPORT = {
721
728
  messages: 0,
722
729
  malformedLines: 0
723
730
  };
731
+ async function upsertIndexedConversation(corpus, record, index) {
732
+ const result = await corpus.upsert(record);
733
+ if (index) {
734
+ const saved = await corpus.getFromPlatform(record.conversation.platform, result.docId);
735
+ if (!saved) {
736
+ throw new Error(`Saved conversation '${result.docId}' could not be read for indexing`);
737
+ }
738
+ index.upsertConversation(saved);
739
+ }
740
+ return result;
741
+ }
724
742
  async function ingestFile(corpus, file, index) {
725
743
  const report = { ...EMPTY_REPORT };
726
744
  let current = null;
@@ -730,11 +748,8 @@ async function ingestFile(corpus, file, index) {
730
748
  return;
731
749
  }
732
750
  const record = { conversation: current, messages: buffered };
733
- const result = await corpus.upsert(record);
751
+ const result = await upsertIndexedConversation(corpus, record, index);
734
752
  tally(report, result);
735
- if (index && result.outcome !== "skipped") {
736
- index.upsertConversation(record);
737
- }
738
753
  report.conversations += 1;
739
754
  report.messages += buffered.length;
740
755
  current = null;
@@ -771,9 +786,9 @@ async function ingestFile(corpus, file, index) {
771
786
  }
772
787
  continue;
773
788
  }
774
- if (type === "message" && current) {
789
+ if (type === "message") {
775
790
  const docId = typeof record.docId === "string" ? record.docId : "";
776
- if (docId !== current.docId) {
791
+ if (!current || docId !== current.docId) {
777
792
  report.malformedLines += 1;
778
793
  continue;
779
794
  }
@@ -1044,6 +1059,8 @@ CREATE TABLE IF NOT EXISTS conversations (
1044
1059
  pinned INTEGER NOT NULL,
1045
1060
  accountId TEXT,
1046
1061
  accountLabel TEXT,
1062
+ providerProject TEXT,
1063
+ providerWorkspace TEXT,
1047
1064
  models TEXT,
1048
1065
  fingerprint TEXT NOT NULL
1049
1066
  );
@@ -1113,14 +1130,14 @@ var SearchIndex = class {
1113
1130
  deleteFts: this.db.prepare("DELETE FROM messages_fts WHERE rowid = ?"),
1114
1131
  deleteMessageRows: this.db.prepare("DELETE FROM message_rows WHERE docId = ?"),
1115
1132
  insertMessageRow: this.db.prepare(
1116
- "INSERT INTO message_rows (docId, msgIndex, role) VALUES (?, ?, ?)"
1133
+ "INSERT INTO message_rows (docId, msgIndex, role) VALUES (?, ?, ?) RETURNING rowid"
1117
1134
  ),
1118
1135
  insertFts: this.db.prepare("INSERT INTO messages_fts (rowid, text) VALUES (?, ?)"),
1119
1136
  deleteConversation: this.db.prepare("DELETE FROM conversations WHERE docId = ?"),
1120
1137
  insertConversation: this.db.prepare(
1121
1138
  `INSERT INTO conversations
1122
- (docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned, accountId, accountLabel, models, fingerprint)
1123
- VALUES (@docId, @platform, @title, @url, @createdAt, @updatedAt, @messageCount, @preview, @pinned, @accountId, @accountLabel, @models, @fingerprint)`
1139
+ (docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned, accountId, accountLabel, providerProject, providerWorkspace, models, fingerprint)
1140
+ VALUES (@docId, @platform, @title, @url, @createdAt, @updatedAt, @messageCount, @preview, @pinned, @accountId, @accountLabel, @providerProject, @providerWorkspace, @models, @fingerprint)`
1124
1141
  ),
1125
1142
  deleteMemoryFts: this.db.prepare("DELETE FROM memories_fts WHERE memoryId = ?"),
1126
1143
  insertMemoryFts: this.db.prepare(
@@ -1139,6 +1156,8 @@ var SearchIndex = class {
1139
1156
  FROM temp.snippet_fts WHERE snippet_fts MATCH ?`
1140
1157
  )
1141
1158
  };
1159
+ this.stmts.selectFtsRows.setReadBigInts(true);
1160
+ this.stmts.insertMessageRow.setReadBigInts(true);
1142
1161
  }
1143
1162
  /** True when the stored format version was missing or stale — caller rebuilds. */
1144
1163
  needsRebuild() {
@@ -1164,14 +1183,18 @@ var SearchIndex = class {
1164
1183
  const orderBy = sort === "oldest" ? "createdAt ASC, updatedAt ASC" : sort === "newest" ? "createdAt DESC, updatedAt DESC" : "updatedAt DESC, createdAt DESC";
1165
1184
  const rows = this.db.prepare(
1166
1185
  `SELECT docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned,
1167
- accountId, accountLabel, models
1186
+ accountId, accountLabel, providerProject, providerWorkspace, models
1168
1187
  FROM conversations ORDER BY ${orderBy} LIMIT ?`
1169
1188
  ).all(limit);
1170
1189
  return rows.map((r) => {
1171
- const { accountId, accountLabel, models, ...rest } = r;
1190
+ const { accountId, accountLabel, providerProject, providerWorkspace, models, ...rest } = r;
1172
1191
  const entry = { ...rest, pinned: r.pinned === 1 };
1173
1192
  if (accountId) entry.accountId = accountId;
1174
1193
  if (accountLabel) entry.accountLabel = accountLabel;
1194
+ const project = parseObservation(providerProject);
1195
+ if (project) entry.providerProject = project;
1196
+ const workspace = parseObservation(providerWorkspace);
1197
+ if (workspace) entry.providerWorkspace = workspace;
1175
1198
  const parsedModels = parseModels(models);
1176
1199
  if (parsedModels.length > 0) entry.models = parsedModels;
1177
1200
  return entry;
@@ -1277,13 +1300,15 @@ var SearchIndex = class {
1277
1300
  pinned: conversation.pinned ? 1 : 0,
1278
1301
  accountId: conversation.accountId ?? null,
1279
1302
  accountLabel: conversation.accountLabel ?? null,
1303
+ providerProject: observationJson(conversation.providerProject),
1304
+ providerWorkspace: observationJson(conversation.providerWorkspace),
1280
1305
  models: conversation.models?.length ? JSON.stringify(conversation.models) : null,
1281
1306
  fingerprint: fingerprintConversation(rec)
1282
1307
  });
1283
1308
  }
1284
1309
  insertFtsRow(docId, msgIndex, role, text) {
1285
- const inserted = this.stmts.insertMessageRow.run(docId, msgIndex, role);
1286
- this.stmts.insertFts.run(inserted.lastInsertRowid, text);
1310
+ const inserted = this.stmts.insertMessageRow.get(docId, msgIndex, role);
1311
+ this.stmts.insertFts.run(inserted.rowid, text);
1287
1312
  }
1288
1313
  deleteFtsRows(docId) {
1289
1314
  const rows = this.stmts.selectFtsRows.all(docId);
@@ -1339,11 +1364,20 @@ var SearchIndex = class {
1339
1364
  clauses.push("c.createdAt <= @dateTo");
1340
1365
  params.dateTo = filters.dateTo;
1341
1366
  }
1367
+ if (filters.providerProjectId) {
1368
+ clauses.push("json_extract(c.providerProject, '$.projectId') = @providerProjectId");
1369
+ params.providerProjectId = filters.providerProjectId;
1370
+ }
1371
+ if (filters.providerWorkspaceId) {
1372
+ clauses.push("json_extract(c.providerWorkspace, '$.workspaceId') = @providerWorkspaceId");
1373
+ params.providerWorkspaceId = filters.providerWorkspaceId;
1374
+ }
1342
1375
  const scanCap = Math.min(2e3, Math.max(200, limit * 40));
1343
1376
  const sql = `
1344
1377
  SELECT
1345
1378
  c.docId, c.platform, c.title, c.url, c.createdAt, c.updatedAt,
1346
- c.messageCount, c.preview, c.pinned, c.accountId, c.accountLabel, c.models,
1379
+ c.messageCount, c.preview, c.pinned, c.accountId, c.accountLabel,
1380
+ c.providerProject, c.providerWorkspace, c.models,
1347
1381
  m.msgIndex AS msgIndex, m.role AS role,
1348
1382
  bm25(messages_fts) AS bm25
1349
1383
  FROM messages_fts
@@ -1379,6 +1413,10 @@ var SearchIndex = class {
1379
1413
  };
1380
1414
  if (row.accountId) hit.accountId = row.accountId;
1381
1415
  if (row.accountLabel) hit.accountLabel = row.accountLabel;
1416
+ const project = parseObservation(row.providerProject);
1417
+ if (project) hit.providerProject = project;
1418
+ const workspace = parseObservation(row.providerWorkspace);
1419
+ if (workspace) hit.providerWorkspace = workspace;
1382
1420
  const models = parseModels(row.models);
1383
1421
  if (models.length > 0) hit.models = models;
1384
1422
  hits.push(hit);
@@ -1474,6 +1512,19 @@ function parseModels(value) {
1474
1512
  return [];
1475
1513
  }
1476
1514
  }
1515
+ function observationJson(observation) {
1516
+ if (!observation) return null;
1517
+ return JSON.stringify(observation);
1518
+ }
1519
+ function parseObservation(value) {
1520
+ if (!value) return void 0;
1521
+ try {
1522
+ const parsed = JSON.parse(value);
1523
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
1524
+ } catch {
1525
+ return void 0;
1526
+ }
1527
+ }
1477
1528
 
1478
1529
  // src/storageMaintenance.ts
1479
1530
  import { promises as fs4 } from "fs";
@@ -2147,6 +2198,7 @@ export {
2147
2198
  resolveCorpusDir,
2148
2199
  staleIndexFiles,
2149
2200
  Corpus,
2201
+ upsertIndexedConversation,
2150
2202
  ingestFile,
2151
2203
  pendingInboxFiles,
2152
2204
  drainInbox,
@@ -17,13 +17,13 @@ import {
17
17
  runtimeBinDir,
18
18
  staleIndexFiles,
19
19
  uninstallRuntime
20
- } from "./chunk-BWEDXPNM.js";
20
+ } from "./chunk-XRA6OJC5.js";
21
21
  import {
22
22
  VERSION,
23
23
  __commonJS,
24
24
  __require,
25
25
  __toESM
26
- } from "./chunk-YT6GNKKG.js";
26
+ } from "./chunk-GLCLSBT6.js";
27
27
 
28
28
  // ../node_modules/isexe/windows.js
29
29
  var require_windows = __commonJS({
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-YT6GNKKG.js";
6
+ } from "./chunk-GLCLSBT6.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-KHY7ADCU.js");
144
+ const { main } = await import("./cli-2IIJ77ZQ.js");
145
145
  return main();
146
146
  }
147
147
  bootstrap().then((code) => {
@@ -78,9 +78,29 @@ const DEFAULT_CODEX_HOME = process.env.CODEX_HOME || join(homedir(), ".codex");
78
78
  // Codex nests rollouts as sessions/<year>/<month>/<day>/*.jsonl. Bounded so a
79
79
  // misconfigured codexHome can't turn into an unbounded filesystem walk.
80
80
  const CODEX_MAX_DEPTH = 3;
81
- // Conservative chunk size (chars). After JSON-escaping + any multibyte chars the
82
- // on-wire message stays well under native messaging's 1 MB per-message ceiling.
83
- const CHUNK_CHARS = 256 * 1024;
81
+ // Conservative chunk size. Native messaging caps a single message at 1 MB,
82
+ // and the wire size of a chunk is the JSON-ESCAPED UTF-8 length of `data`
83
+ // (an astral character is 4 raw bytes; a literal backslash doubles), so
84
+ // chunks are budgeted by measuring exactly that as they are built: a chunk
85
+ // can never push the framed message over the ceiling no matter what the
86
+ // transcript contains.
87
+ const MAX_CHUNK_ESCAPED_BYTES = 256 * 1024;
88
+ // JSON-escaped UTF-8 byte length of one UTF-16 code unit of `text` as
89
+ // JSON.stringify would emit it: quotes/backslashes and the short escapes
90
+ // double, other control characters become \u00XX (6 bytes), a lone surrogate
91
+ // becomes \udXXX, BMP non-ASCII passes through at its UTF-8 width, and a
92
+ // surrogate PAIR is one 4-byte astral character.
93
+ function escapedUnitBytes(unit, nextUnit) {
94
+ if (unit >= 0xd800 && unit <= 0xdbff) {
95
+ return nextUnit >= 0xdc00 && nextUnit <= 0xdfff ? 4 : 6; // astral char or lone high surrogate
96
+ }
97
+ if (unit >= 0xdc00 && unit <= 0xdfff) return 6; // lone low surrogate
98
+ if (unit === 0x22 || unit === 0x5c) return 2; // " and \
99
+ if (unit < 0x20) return [0x08, 0x09, 0x0a, 0x0c, 0x0d].includes(unit) ? 2 : 6;
100
+ if (unit < 0x80) return 1;
101
+ if (unit < 0x800) return 2;
102
+ return 3;
103
+ }
84
104
  // Matches companion/src/corpus.ts DIR_MODE/FILE_MODE — the corpus holds
85
105
  // plaintext conversation history, so writes here should be no more readable
86
106
  // than the browser profile it was copied out of.
@@ -690,14 +710,31 @@ async function handle(message) {
690
710
  }
691
711
  text = await readFile(match.path, "utf8");
692
712
  }
693
- const total = Math.max(1, Math.ceil(text.length / CHUNK_CHARS));
694
- for (let i = 0, seq = 0; seq < total; i += CHUNK_CHARS, seq++) {
713
+ const chunks = [];
714
+ let chunk = "";
715
+ let chunkBytes = 0;
716
+ for (let i = 0; i < text.length; i++) {
717
+ const unit = text.charCodeAt(i);
718
+ const size = escapedUnitBytes(unit, i + 1 < text.length ? text.charCodeAt(i + 1) : NaN);
719
+ if (chunk && chunkBytes + size > MAX_CHUNK_ESCAPED_BYTES) {
720
+ chunks.push(chunk);
721
+ chunk = "";
722
+ chunkBytes = 0;
723
+ }
724
+ chunk += text[i];
725
+ chunkBytes += size;
726
+ }
727
+ if (chunk) {
728
+ chunks.push(chunk);
729
+ }
730
+ const total = Math.max(1, chunks.length);
731
+ for (let seq = 0; seq < total; seq++) {
695
732
  send({
696
733
  type: "chunk",
697
734
  sessionId: message.sessionId,
698
735
  seq,
699
736
  total,
700
- data: text.slice(i, i + CHUNK_CHARS)
737
+ data: chunks[seq] ?? ""
701
738
  });
702
739
  }
703
740
  send({ type: "sessionDone", sessionId: message.sessionId });
@@ -728,7 +765,16 @@ process.stdin.on("data", (data) => {
728
765
  // Serialize handling so chunk ordering per session is preserved.
729
766
  processing = processing
730
767
  .then(() => handle(message))
731
- .catch((error) => send({ type: "error", error: String((error && error.message) || error) }));
768
+ .catch((error) =>
769
+ // Attribute the failure to the command's session when it names one, so
770
+ // the extension's fetch loop can drop a STALE error that arrives after
771
+ // it gave up on that session instead of failing the next one.
772
+ send({
773
+ type: "error",
774
+ ...(typeof message.sessionId === "string" ? { sessionId: message.sessionId } : {}),
775
+ error: String((error && error.message) || error)
776
+ })
777
+ );
732
778
  }
733
779
  });
734
780
 
Binary file
package/dist/mcp.js CHANGED
@@ -12,14 +12,15 @@ import {
12
12
  readNativeHostViewerExtensionId,
13
13
  resolveCorpusDir,
14
14
  runAutomaticMaintenance,
15
- scheduleSelfUpdate
16
- } from "./chunk-BWEDXPNM.js";
15
+ scheduleSelfUpdate,
16
+ upsertIndexedConversation
17
+ } from "./chunk-XRA6OJC5.js";
17
18
  import {
18
19
  VERSION,
19
20
  __commonJS,
20
21
  __export,
21
22
  __toESM
22
- } from "./chunk-YT6GNKKG.js";
23
+ } from "./chunk-GLCLSBT6.js";
23
24
 
24
25
  // ../node_modules/ajv/dist/compile/codegen/code.js
25
26
  var require_code = __commonJS({
@@ -21704,10 +21705,7 @@ var CompanionService = class _CompanionService {
21704
21705
  async saveConversation(payload) {
21705
21706
  const input = saveConversationSchema.parse(payload);
21706
21707
  const record2 = normalizeSaveInput(input);
21707
- const result = await this.corpus.upsert(record2);
21708
- if (result.outcome !== "skipped") {
21709
- this.index.upsertConversation(record2);
21710
- }
21708
+ const result = await upsertIndexedConversation(this.corpus, record2, this.index);
21711
21709
  return { docId: result.docId, outcome: result.outcome, messageCount: record2.messages.length };
21712
21710
  }
21713
21711
  /**
@@ -21810,16 +21808,15 @@ function viewerExtensionId() {
21810
21808
  const configured = process.env.LLMNESIA_VIEWER_EXTENSION_ID?.trim() ?? readNativeHostViewerExtensionId();
21811
21809
  return configured && EXTENSION_ID_RE.test(configured) ? configured : STORE_EXTENSION_ID;
21812
21810
  }
21813
- function viewerSourceUrl(docId, extensionId) {
21814
- const fragment = new URLSearchParams({ docId, extensionId });
21811
+ function viewerSourceUrl(docId) {
21812
+ const fragment = new URLSearchParams({ docId });
21815
21813
  return `${VIEWER_HANDOFF_URL}#${fragment.toString()}`;
21816
21814
  }
21817
21815
  function sourceLinks(docId, originalUrl) {
21818
- const extensionId = viewerExtensionId();
21819
- const localViewerUrl = `chrome-extension://${extensionId}/viewer.html?docId=${encodeURIComponent(docId)}`;
21816
+ const localViewerUrl = `chrome-extension://${viewerExtensionId()}/viewer.html?docId=${encodeURIComponent(docId)}`;
21820
21817
  return originalUrl ? { viewerUrl: localViewerUrl, sourceUrl: originalUrl, sourceKind: "original" } : {
21821
21818
  viewerUrl: localViewerUrl,
21822
- sourceUrl: viewerSourceUrl(docId, extensionId),
21819
+ sourceUrl: viewerSourceUrl(docId),
21823
21820
  sourceKind: "viewer"
21824
21821
  };
21825
21822
  }
@@ -21902,6 +21899,8 @@ async function runServe() {
21902
21899
  "How to combine query terms. 'any' (default) ORs them: highest recall, but common words in the query match almost everything, so results cannot be counted or used to prove something was discussed. 'all' requires every term in the same turn. 'phrase' requires the exact wording, adjacent and in order. Use 'all' or 'phrase' for existence and frequency questions, and strip filler words from the query first."
21903
21900
  ),
21904
21901
  platform: external_exports.string().optional().describe("Restrict to one platform, e.g. 'claude', 'chatgpt', 'gemini'."),
21902
+ project_id: external_exports.string().optional().describe("Only conversations observed inside this ChatGPT Project (g-p-...)."),
21903
+ workspace_id: external_exports.string().optional().describe("Only conversations observed under this provider workspace (a Claude organization id)."),
21905
21904
  title: external_exports.string().optional().describe("Only conversations whose title contains this substring."),
21906
21905
  date_from: external_exports.string().optional().describe("Only conversations created on/after this date (ISO or epoch ms)."),
21907
21906
  date_to: external_exports.string().optional().describe("Only conversations created on/before this date (ISO or epoch ms)."),
@@ -21917,6 +21916,8 @@ async function runServe() {
21917
21916
  async (args) => withService(async (service2) => {
21918
21917
  const filters = {
21919
21918
  platform: args.platform,
21919
+ providerProjectId: args.project_id,
21920
+ providerWorkspaceId: args.workspace_id,
21920
21921
  title: args.title,
21921
21922
  dateFrom: parseDate(args.date_from),
21922
21923
  dateTo: parseDate(args.date_to),
@@ -21944,6 +21945,8 @@ async function runServe() {
21944
21945
  };
21945
21946
  if (h.accountId) entry.accountId = h.accountId;
21946
21947
  if (h.accountLabel) entry.accountLabel = h.accountLabel;
21948
+ if (h.providerProject) entry.providerProject = h.providerProject;
21949
+ if (h.providerWorkspace) entry.providerWorkspace = h.providerWorkspace;
21947
21950
  if (h.models?.length) entry.models = h.models;
21948
21951
  return entry;
21949
21952
  })
@@ -22026,6 +22029,8 @@ async function runServe() {
22026
22029
  };
22027
22030
  if (e.accountId) entry.accountId = e.accountId;
22028
22031
  if (e.accountLabel) entry.accountLabel = e.accountLabel;
22032
+ if (e.providerProject) entry.providerProject = e.providerProject;
22033
+ if (e.providerWorkspace) entry.providerWorkspace = e.providerWorkspace;
22029
22034
  if (e.models?.length) entry.models = e.models;
22030
22035
  return entry;
22031
22036
  })
@@ -22070,6 +22075,8 @@ async function runServe() {
22070
22075
  };
22071
22076
  if (e.accountId) entry.accountId = e.accountId;
22072
22077
  if (e.accountLabel) entry.accountLabel = e.accountLabel;
22078
+ if (e.providerProject) entry.providerProject = e.providerProject;
22079
+ if (e.providerWorkspace) entry.providerWorkspace = e.providerWorkspace;
22073
22080
  if (e.models?.length) entry.models = e.models;
22074
22081
  return entry;
22075
22082
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmnesia/mcp",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
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.",
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.2.9",
6
+ "version": "0.2.10",
7
7
  "packages": [
8
8
  {
9
9
  "registryType": "npm",
10
10
  "registryBaseUrl": "https://registry.npmjs.org",
11
11
  "identifier": "@llmnesia/mcp",
12
- "version": "0.2.9",
12
+ "version": "0.2.10",
13
13
  "transport": {
14
14
  "type": "stdio"
15
15
  }