indelible-mcp 4.9.1 → 4.9.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +50 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indelible-mcp",
3
- "version": "4.9.1",
3
+ "version": "4.9.3",
4
4
  "description": "Blockchain-backed memory and code storage for Claude Code. Save AI conversations and source code permanently on BSV.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -3825,7 +3825,8 @@ function deriveTitleSearch(session) {
3825
3825
  };
3826
3826
  const first = msgs.find(isUser) || msgs[0];
3827
3827
  const summary = (session?.summary || "").trim();
3828
- const title = summary || (first ? contentText(first).replace(/\s+/g, " ").trim().slice(0, 90) : "");
3828
+ const firstText = first ? contentText(first).replace(/\s+/g, " ").trim().slice(0, 90) : "";
3829
+ const title = summary && !isGenericSummary(summary) ? summary : firstText || summary;
3829
3830
  const searchText = msgs.map((m) => `${m.role || m.type || ""}: ${contentText(m)}`).join(" \n ").toLowerCase().slice(0, 2e4);
3830
3831
  return { title, searchText, message_count: msgs.length };
3831
3832
  }
@@ -4038,8 +4039,17 @@ async function searchIndexSemantic(address, { fromDate = null, toDate = null, qu
4038
4039
  ordered = [...score.entries()].sort((a, b) => b[1] - a[1]).map(([id]) => byId.get(id)).filter(Boolean);
4039
4040
  ranking_used = "blend";
4040
4041
  }
4042
+ const deduped = [];
4043
+ const seenSig = /* @__PURE__ */ new Set();
4044
+ for (const r of ordered) {
4045
+ const st = r?.searchText || "";
4046
+ const sig = st.length >= 80 ? st.slice(0, 240) : `id:${r.txId}`;
4047
+ if (seenSig.has(sig)) continue;
4048
+ seenSig.add(sig);
4049
+ deduped.push(r);
4050
+ }
4041
4051
  return {
4042
- results: ordered.slice(0, limit).map((r) => ({
4052
+ results: deduped.slice(0, limit).map((r) => ({
4043
4053
  txId: r.txId,
4044
4054
  date: r.date,
4045
4055
  title: r.title,
@@ -4062,7 +4072,7 @@ function indexStatus(address) {
4062
4072
  index_file: indexPath(address)
4063
4073
  };
4064
4074
  }
4065
- var ROOT, INDEX_DIR2, GAPS_DIR, indexPath, indexLock, gapsPath, gapsLock, withTimeout, MIN_SEMANTIC_CHARS, SUBSTANTIAL_CHARS;
4075
+ var ROOT, INDEX_DIR2, GAPS_DIR, indexPath, indexLock, gapsPath, gapsLock, withTimeout, isGenericSummary, MIN_SEMANTIC_CHARS, SUBSTANTIAL_CHARS;
4066
4076
  var init_recall_index = __esm({
4067
4077
  "lib/recall-index.js"() {
4068
4078
  init_file_lock();
@@ -4076,6 +4086,7 @@ var init_recall_index = __esm({
4076
4086
  gapsPath = (a) => join16(GAPS_DIR, `${a}.jsonl`);
4077
4087
  gapsLock = (a) => join16(GAPS_DIR, `${a}.lock`);
4078
4088
  withTimeout = (p, ms) => Promise.race([p, new Promise((_, rej) => setTimeout(() => rej(new Error("fetch timeout")), ms))]);
4089
+ isGenericSummary = (s) => /^(auto[-\s]?save|auto[-\s]?compaction|checkpoint|save[-_\s]?all|delta[-\s]?save)\b/i.test(s || "");
4079
4090
  MIN_SEMANTIC_CHARS = 140;
4080
4091
  SUBSTANTIAL_CHARS = 1200;
4081
4092
  }
@@ -7978,7 +7989,7 @@ Commands:
7978
7989
  }
7979
7990
  function printHelp() {
7980
7991
  console.log(`
7981
- Indelible MCP \u2014 Blockchain memory for Claude Code (v4.9.1)
7992
+ Indelible MCP \u2014 Blockchain memory for Claude Code (v4.9.3)
7982
7993
 
7983
7994
  Setup:
7984
7995
  indelible-mcp setup --wif=KEY --pin=PIN Import and encrypt your private key
@@ -8025,13 +8036,41 @@ Get your key: Sign in at indelible.one \u2192 Settings \u2192 Private Key
8025
8036
  Learn more: https://indelible.one
8026
8037
  `);
8027
8038
  }
8039
+ function findNewestTranscript() {
8040
+ const projectsDir = join19(homedir15(), ".claude", "projects");
8041
+ if (!existsSync19(projectsDir)) return null;
8042
+ let newestTime = 0;
8043
+ let newest = null;
8044
+ try {
8045
+ for (const project of readdirSync(projectsDir)) {
8046
+ const projectPath = join19(projectsDir, project);
8047
+ try {
8048
+ if (!statSync4(projectPath).isDirectory()) continue;
8049
+ for (const file of readdirSync(projectPath)) {
8050
+ if (!file.endsWith(".jsonl")) continue;
8051
+ const p = join19(projectPath, file);
8052
+ const t = statSync4(p).mtimeMs;
8053
+ if (t > newestTime) {
8054
+ newestTime = t;
8055
+ newest = p;
8056
+ }
8057
+ }
8058
+ } catch {
8059
+ }
8060
+ }
8061
+ } catch {
8062
+ }
8063
+ return newest;
8064
+ }
8028
8065
  async function runPreCompactSave() {
8029
8066
  let trigger = "auto";
8067
+ let transcriptPath = null;
8030
8068
  try {
8031
8069
  const stdin = await readStdin();
8032
8070
  if (stdin) {
8033
8071
  const meta = JSON.parse(stdin);
8034
8072
  trigger = meta.trigger || "auto";
8073
+ transcriptPath = meta.transcript_path || null;
8035
8074
  }
8036
8075
  } catch {
8037
8076
  }
@@ -8040,7 +8079,8 @@ async function runPreCompactSave() {
8040
8079
  process.stderr.write("Indelible: MCP disabled, skipping save\n");
8041
8080
  process.exit(0);
8042
8081
  }
8043
- const result = await saveSession(CONTEXT_FILE2, `Auto-save before ${trigger} compaction`);
8082
+ const target = transcriptPath && existsSync19(transcriptPath) ? transcriptPath : findNewestTranscript() || CONTEXT_FILE2;
8083
+ const result = await saveSession(target, `Auto-save before ${trigger} compaction`);
8044
8084
  if (result.success) {
8045
8085
  process.stderr.write(`Indelible: Saved ${result.newMessages} messages (${result.saveType}) tx:${result.txId?.slice(0, 12)}...
8046
8086
  `);
@@ -8198,7 +8238,7 @@ function readStdin() {
8198
8238
  }
8199
8239
  var SERVER_INFO = {
8200
8240
  name: "indelible",
8201
- version: "4.9.1",
8241
+ version: "4.9.3",
8202
8242
  description: "Blockchain-backed memory and code storage for Claude Code"
8203
8243
  };
8204
8244
  var TOOLS = [
@@ -8495,7 +8535,8 @@ var TOOLS = [
8495
8535
  depth: { type: "string", enum: ["list", "full"], description: '"list" (default) = Tier-1 search; "full" = decrypt given txids.' },
8496
8536
  limit: { type: "number", description: 'Max results for depth:"list" (default 25).' },
8497
8537
  txids: { type: "array", items: { type: "string" }, description: 'For depth:"full": session txids to decrypt (max 20).' },
8498
- max_index: { type: "number", description: "Max sessions to decrypt-and-index this call (default 150)." }
8538
+ max_index: { type: "number", description: "Max sessions to decrypt-and-index this call (default 150)." },
8539
+ ranking: { type: "string", enum: ["blend", "keyword", "semantic"], description: "Result ranking: 'blend' (default) fuses keyword + meaning-based ranking; 'keyword' = exact-term only; 'semantic' = meaning only. Meaning ranking needs the local model pack (indelible-mcp semantic-fetch); absent = keyword with a notice. Nothing ever leaves your machine." }
8499
8540
  },
8500
8541
  required: []
8501
8542
  }
@@ -8652,7 +8693,8 @@ async function handleMcpRequest(request) {
8652
8693
  depth: args2?.depth || "list",
8653
8694
  limit: args2?.limit || 25,
8654
8695
  txids: args2?.txids || null,
8655
- max_index: args2?.max_index || 150
8696
+ max_index: args2?.max_index || 150,
8697
+ ranking: args2?.ranking || "blend"
8656
8698
  });
8657
8699
  break;
8658
8700
  case "report_bug":