indelible-mcp 4.8.1 → 4.8.2
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/package.json +1 -1
- package/src/index.js +155 -21
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1590,6 +1590,14 @@ function detectSaveFormat(payload) {
|
|
|
1590
1590
|
if (payload && typeof payload.wrap_owner === "string" && payload.wrap_owner.length > 0) return "v2-wrapped";
|
|
1591
1591
|
return "legacy";
|
|
1592
1592
|
}
|
|
1593
|
+
function detectVaultFormat(payload) {
|
|
1594
|
+
if (!payload) return "legacy";
|
|
1595
|
+
return detectSaveFormat({
|
|
1596
|
+
wrap_owner: payload.wrap_owner,
|
|
1597
|
+
wrap_self: payload.wrap_self,
|
|
1598
|
+
wrap_version: payload.wrap_version
|
|
1599
|
+
});
|
|
1600
|
+
}
|
|
1593
1601
|
function generateContentKey() {
|
|
1594
1602
|
return randomBytes3(32);
|
|
1595
1603
|
}
|
|
@@ -5244,12 +5252,41 @@ ${formatSaveReceipt(receipt)}`
|
|
|
5244
5252
|
// mcp-server/tools/load_file.js
|
|
5245
5253
|
init_config_customer();
|
|
5246
5254
|
init_crypto();
|
|
5247
|
-
init_spv();
|
|
5248
5255
|
import { gunzipSync as gunzipSync2 } from "zlib";
|
|
5249
5256
|
import { writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
5250
5257
|
import { existsSync as existsSync11 } from "fs";
|
|
5251
5258
|
import { dirname as dirname2 } from "path";
|
|
5252
|
-
import { Transaction as Transaction6 } from "@bsv/sdk";
|
|
5259
|
+
import { Transaction as Transaction6, PrivateKey as PrivateKey8, CompletedProtoWallet as CompletedProtoWallet3 } from "@bsv/sdk";
|
|
5260
|
+
init_spv();
|
|
5261
|
+
async function unwrapVaultV3(payload, wif) {
|
|
5262
|
+
let w = null;
|
|
5263
|
+
try {
|
|
5264
|
+
w = new CompletedProtoWallet3(PrivateKey8.fromWif(wif));
|
|
5265
|
+
} catch {
|
|
5266
|
+
w = null;
|
|
5267
|
+
}
|
|
5268
|
+
if (!w) return { ok: false, code: "WALLET_UNAVAILABLE" };
|
|
5269
|
+
if (payload.owner_pubkey) {
|
|
5270
|
+
let idPub = null;
|
|
5271
|
+
try {
|
|
5272
|
+
idPub = (await w.getPublicKey({ identityKey: true }))?.publicKey || null;
|
|
5273
|
+
} catch {
|
|
5274
|
+
}
|
|
5275
|
+
if (idPub && idPub !== payload.owner_pubkey) {
|
|
5276
|
+
if (payload.wrap_recovery) {
|
|
5277
|
+
const rr = await unwrapRecoveryV3(payload.wrap_recovery, w, payload.key_id, payload.owner_pubkey);
|
|
5278
|
+
if (rr.ok) return { ok: true, contentKey: rr.contentKey };
|
|
5279
|
+
}
|
|
5280
|
+
return { ok: false, code: "WALLET_UNAVAILABLE" };
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
let r = await unwrapForSelfV3(payload.wrap_self, w, payload.key_id);
|
|
5284
|
+
if (!r.ok && r.reason === "corrupt" && payload.wrap_recovery && payload.owner_pubkey) {
|
|
5285
|
+
r = await unwrapRecoveryV3(payload.wrap_recovery, w, payload.key_id, payload.owner_pubkey);
|
|
5286
|
+
}
|
|
5287
|
+
if (!r.ok) return { ok: false, code: r.reason === "wallet_unavailable" ? "WALLET_UNAVAILABLE" : "V3_CORRUPT" };
|
|
5288
|
+
return { ok: true, contentKey: r.contentKey };
|
|
5289
|
+
}
|
|
5253
5290
|
async function fetchJsonPayload(txId) {
|
|
5254
5291
|
const cleanTxId = txId.trim();
|
|
5255
5292
|
try {
|
|
@@ -5299,6 +5336,47 @@ async function loadFile(txId, options = {}) {
|
|
|
5299
5336
|
if (payload.protocol !== "indelible.file") {
|
|
5300
5337
|
return { success: false, error: `Not an indelible.file tx (got: ${payload.protocol || "unknown"})` };
|
|
5301
5338
|
}
|
|
5339
|
+
const vfmt = detectVaultFormat(payload);
|
|
5340
|
+
if (vfmt === "v3-wallet") {
|
|
5341
|
+
const uv = await unwrapVaultV3(payload, wif);
|
|
5342
|
+
if (!uv.ok) {
|
|
5343
|
+
return { success: false, code: uv.code, error: uv.code === "WALLET_UNAVAILABLE" ? "wallet-native file: not readable from this box \u2014 its key lives in an external wallet (open it in the web app), or this WIF is not the owner" : "wallet-native file: unwrap failed (corrupt or wrong wallet)" };
|
|
5344
|
+
}
|
|
5345
|
+
let outBuf2;
|
|
5346
|
+
try {
|
|
5347
|
+
const dec = decryptWithKey(payload.encrypted, Buffer.from(uv.contentKey));
|
|
5348
|
+
outBuf2 = dec.startsWith("gz:") ? gunzipSync2(Buffer.from(dec.slice(3), "base64")) : Buffer.from(dec, "utf8");
|
|
5349
|
+
} catch (err) {
|
|
5350
|
+
return { success: false, code: "V3_CORRUPT", error: `wallet-native decrypt failed: ${err.message}` };
|
|
5351
|
+
}
|
|
5352
|
+
const contentHash2 = sha256(outBuf2);
|
|
5353
|
+
let meta = {};
|
|
5354
|
+
try {
|
|
5355
|
+
meta = JSON.parse(decryptWithKey(payload.meta_enc, Buffer.from(uv.contentKey)));
|
|
5356
|
+
} catch {
|
|
5357
|
+
}
|
|
5358
|
+
const verified2 = meta.sha256 ? contentHash2 === meta.sha256 : payload.content_hash ? contentHash2 === payload.content_hash.replace("sha256:", "") : null;
|
|
5359
|
+
if (options.outputPath) {
|
|
5360
|
+
const dir = dirname2(options.outputPath);
|
|
5361
|
+
if (!existsSync11(dir)) await mkdir4(dir, { recursive: true });
|
|
5362
|
+
await writeFile4(options.outputPath, outBuf2);
|
|
5363
|
+
}
|
|
5364
|
+
const isBinary2 = payload.enc === "b64";
|
|
5365
|
+
return {
|
|
5366
|
+
success: true,
|
|
5367
|
+
txId,
|
|
5368
|
+
wallet_native: true,
|
|
5369
|
+
filename: meta.filename,
|
|
5370
|
+
path: meta.path,
|
|
5371
|
+
size: payload.size,
|
|
5372
|
+
content_hash: payload.content_hash,
|
|
5373
|
+
verified: verified2,
|
|
5374
|
+
content: isBinary2 ? `[binary file: ${outBuf2.length} bytes${options.outputPath ? ", written to disk" : ""}]` : outBuf2.toString("utf8")
|
|
5375
|
+
};
|
|
5376
|
+
}
|
|
5377
|
+
if (vfmt === "v3-malformed") {
|
|
5378
|
+
return { success: false, code: "V3_CORRUPT", error: "file carries malformed v3 wrap fields \u2014 failing closed" };
|
|
5379
|
+
}
|
|
5302
5380
|
let encrypted;
|
|
5303
5381
|
if (payload._chunks) {
|
|
5304
5382
|
let encryptedParts = "";
|
|
@@ -5363,11 +5441,12 @@ async function loadFile(txId, options = {}) {
|
|
|
5363
5441
|
// mcp-server/tools/load_project.js
|
|
5364
5442
|
init_config_customer();
|
|
5365
5443
|
init_crypto();
|
|
5366
|
-
|
|
5444
|
+
import { gunzipSync as gunzipSync3 } from "zlib";
|
|
5367
5445
|
import { mkdir as mkdir5 } from "fs/promises";
|
|
5368
5446
|
import { existsSync as existsSync12 } from "fs";
|
|
5369
5447
|
import { join as join11, dirname as dirname3 } from "path";
|
|
5370
5448
|
import { Transaction as Transaction7 } from "@bsv/sdk";
|
|
5449
|
+
init_spv();
|
|
5371
5450
|
async function fetchJsonPayload2(txId) {
|
|
5372
5451
|
const cleanTxId = txId.trim();
|
|
5373
5452
|
try {
|
|
@@ -5420,6 +5499,61 @@ async function loadProject(txId, options = {}) {
|
|
|
5420
5499
|
if (!manifest.files || !Array.isArray(manifest.files)) {
|
|
5421
5500
|
return { success: false, error: "Manifest has no files array" };
|
|
5422
5501
|
}
|
|
5502
|
+
if (detectVaultFormat(manifest) === "v3-wallet") {
|
|
5503
|
+
const uv = await unwrapVaultV3(manifest, wif);
|
|
5504
|
+
if (!uv.ok) {
|
|
5505
|
+
return { success: false, code: uv.code, error: uv.code === "WALLET_UNAVAILABLE" ? "wallet-native project: not readable from this box \u2014 open it in the web app with the wallet that saved it" : "wallet-native project: manifest unwrap failed (corrupt or wrong wallet)" };
|
|
5506
|
+
}
|
|
5507
|
+
const ck = Buffer.from(uv.contentKey);
|
|
5508
|
+
const dk = (s) => decryptWithKey(s, ck);
|
|
5509
|
+
let sealed = {};
|
|
5510
|
+
try {
|
|
5511
|
+
sealed = JSON.parse(dk(manifest.name_enc));
|
|
5512
|
+
} catch {
|
|
5513
|
+
}
|
|
5514
|
+
const v3Files = [];
|
|
5515
|
+
const v3Errors = [];
|
|
5516
|
+
for (const fileRef of manifest.files) {
|
|
5517
|
+
try {
|
|
5518
|
+
const meta = JSON.parse(dk(fileRef.meta_enc));
|
|
5519
|
+
const dec = dk(fileRef.encrypted);
|
|
5520
|
+
const outBuf = dec.startsWith("gz:") ? gunzipSync3(Buffer.from(dec.slice(3), "base64")) : Buffer.from(dec, "utf8");
|
|
5521
|
+
const verified = meta.sha256 ? sha256(outBuf) === meta.sha256 : null;
|
|
5522
|
+
if (verified === false) {
|
|
5523
|
+
v3Errors.push({ path: "(tampered)", error: "content hash mismatch vs sealed meta" });
|
|
5524
|
+
continue;
|
|
5525
|
+
}
|
|
5526
|
+
if (options.outputDir) {
|
|
5527
|
+
const outputPath = join11(options.outputDir, sealed.name || "project", meta.path);
|
|
5528
|
+
const dir = dirname3(outputPath);
|
|
5529
|
+
if (!existsSync12(dir)) await mkdir5(dir, { recursive: true });
|
|
5530
|
+
const { writeFile: writeFile5 } = await import("fs/promises");
|
|
5531
|
+
await writeFile5(outputPath, outBuf);
|
|
5532
|
+
}
|
|
5533
|
+
const isBinary = fileRef.enc === "b64";
|
|
5534
|
+
v3Files.push({ path: meta.path, size: fileRef.size, verified, content: options.outputDir ? void 0 : isBinary ? `[binary: ${outBuf.length} bytes]` : outBuf.toString("utf8") });
|
|
5535
|
+
} catch (err) {
|
|
5536
|
+
v3Errors.push({ path: "(locked)", error: err.message });
|
|
5537
|
+
}
|
|
5538
|
+
}
|
|
5539
|
+
const setOk = sealed.file_count == null || sealed.file_count === manifest.files.length;
|
|
5540
|
+
return {
|
|
5541
|
+
success: true,
|
|
5542
|
+
txId,
|
|
5543
|
+
wallet_native: true,
|
|
5544
|
+
projectName: sealed.name,
|
|
5545
|
+
fileCount: sealed.file_count ?? manifest.files.length,
|
|
5546
|
+
set_integrity: setOk ? "ok" : "FAILED",
|
|
5547
|
+
totalSize: manifest.total_size,
|
|
5548
|
+
loadedFiles: v3Files.length,
|
|
5549
|
+
files: v3Files,
|
|
5550
|
+
errors: v3Errors.length ? v3Errors : void 0,
|
|
5551
|
+
message: `Project "${sealed.name || ""}" loaded (wallet-native): ${v3Files.length}/${sealed.file_count ?? manifest.files.length} files${setOk ? "" : " \u2014 \u26A0\uFE0F SET-INTEGRITY MISMATCH"}`
|
|
5552
|
+
};
|
|
5553
|
+
}
|
|
5554
|
+
if (detectVaultFormat(manifest) === "v3-malformed") {
|
|
5555
|
+
return { success: false, code: "V3_CORRUPT", error: "project manifest carries malformed v3 wrap fields \u2014 failing closed" };
|
|
5556
|
+
}
|
|
5423
5557
|
const isBundle = manifest.protocol === "indelible.project-bundle";
|
|
5424
5558
|
const projectName = manifest.name_enc ? decrypt(manifest.name_enc, wif) : manifest.name;
|
|
5425
5559
|
const loadedFiles = [];
|
|
@@ -5496,20 +5630,20 @@ async function updateVaultIndex() {
|
|
|
5496
5630
|
if (!_gate.ok) return { success: false, gated: true, plan: _gate.plan, upsell: _gate.upsell, error: _gate.error };
|
|
5497
5631
|
const files = config.file_txids || [];
|
|
5498
5632
|
const projects = config.project_txids || [];
|
|
5499
|
-
const encFiles = files.map((f) =>
|
|
5633
|
+
const encFiles = files.map((f) => f.filename ? {
|
|
5500
5634
|
txid: f.txId,
|
|
5501
|
-
filename_enc: encrypt(f.filename
|
|
5502
|
-
path_enc: encrypt(f.path ||
|
|
5635
|
+
filename_enc: encrypt(f.filename, wif),
|
|
5636
|
+
path_enc: encrypt(f.path || f.filename, wif),
|
|
5503
5637
|
size: f.size || 0,
|
|
5504
5638
|
timestamp: f.timestamp || null
|
|
5505
|
-
})
|
|
5506
|
-
const encProjects = projects.map((p) =>
|
|
5639
|
+
} : { txid: f.txId, size: f.size || 0, timestamp: f.timestamp || null, wrap: "v3" });
|
|
5640
|
+
const encProjects = projects.map((p) => p.name ? {
|
|
5507
5641
|
txid: p.txId,
|
|
5508
|
-
name_enc: encrypt(p.name
|
|
5642
|
+
name_enc: encrypt(p.name, wif),
|
|
5509
5643
|
fileCount: p.fileCount || 0,
|
|
5510
5644
|
totalSize: p.totalSize || 0,
|
|
5511
5645
|
timestamp: p.timestamp || null
|
|
5512
|
-
})
|
|
5646
|
+
} : { txid: p.txId, fileCount: p.fileCount || 0, totalSize: p.totalSize || 0, timestamp: p.timestamp || null, wrap: "v3" });
|
|
5513
5647
|
const payload = {
|
|
5514
5648
|
protocol: "indelible.vault-index",
|
|
5515
5649
|
version: 1,
|
|
@@ -6168,7 +6302,7 @@ ${context}` });
|
|
|
6168
6302
|
init_config_customer();
|
|
6169
6303
|
init_spv();
|
|
6170
6304
|
init_utxo_cache();
|
|
6171
|
-
import { PrivateKey as
|
|
6305
|
+
import { PrivateKey as PrivateKey9 } from "@bsv/sdk";
|
|
6172
6306
|
var DEFAULT_MAX_SATS = 1e4;
|
|
6173
6307
|
async function x402Fetch({ url, method = "GET", headers = {}, body, maxSats }) {
|
|
6174
6308
|
const cap = typeof maxSats === "number" && maxSats > 0 ? maxSats : DEFAULT_MAX_SATS;
|
|
@@ -6229,7 +6363,7 @@ async function x402Fetch({ url, method = "GET", headers = {}, body, maxSats }) {
|
|
|
6229
6363
|
pricing
|
|
6230
6364
|
};
|
|
6231
6365
|
}
|
|
6232
|
-
const privateKey =
|
|
6366
|
+
const privateKey = PrivateKey9.fromWif(wif);
|
|
6233
6367
|
const address = privateKey.toPublicKey().toAddress();
|
|
6234
6368
|
let utxos;
|
|
6235
6369
|
try {
|
|
@@ -6314,10 +6448,10 @@ init_utxo_cache();
|
|
|
6314
6448
|
init_config_customer();
|
|
6315
6449
|
init_api_client();
|
|
6316
6450
|
import crypto from "crypto";
|
|
6317
|
-
import { PrivateKey as
|
|
6451
|
+
import { PrivateKey as PrivateKey10 } from "@bsv/sdk";
|
|
6318
6452
|
var GOALS_PATH2 = goalsPath("");
|
|
6319
6453
|
function deriveAddress(wif) {
|
|
6320
|
-
return
|
|
6454
|
+
return PrivateKey10.fromWif(wif).toAddress().toString();
|
|
6321
6455
|
}
|
|
6322
6456
|
function encryptGoals(goalsData, wif) {
|
|
6323
6457
|
const key = crypto.createHash("sha256").update(wif).digest();
|
|
@@ -6584,12 +6718,12 @@ init_spv();
|
|
|
6584
6718
|
init_api_client();
|
|
6585
6719
|
import {
|
|
6586
6720
|
Transaction as Transaction8,
|
|
6587
|
-
PrivateKey as
|
|
6721
|
+
PrivateKey as PrivateKey11,
|
|
6588
6722
|
P2PKH as P2PKH3,
|
|
6589
6723
|
SatoshisPerKilobyte as SatoshisPerKilobyte3,
|
|
6590
6724
|
LockingScript as LockingScript3,
|
|
6591
6725
|
OP as OP3,
|
|
6592
|
-
CompletedProtoWallet as
|
|
6726
|
+
CompletedProtoWallet as CompletedProtoWallet4,
|
|
6593
6727
|
AuthFetch as AuthFetch2
|
|
6594
6728
|
} from "@bsv/sdk";
|
|
6595
6729
|
var SHARE_DUST_SATS = 546;
|
|
@@ -6664,14 +6798,14 @@ async function shareSession({ session_txid, recipient_addr, expires_at = null })
|
|
|
6664
6798
|
if (!wif) return { success: false, error: "wallet not configured \u2014 run setup_wallet first" };
|
|
6665
6799
|
const _gate = await requireProForWrite(config.address);
|
|
6666
6800
|
if (!_gate.ok) return { success: false, gated: true, plan: _gate.plan, upsell: _gate.upsell, error: _gate.error };
|
|
6667
|
-
const ownerPriv =
|
|
6801
|
+
const ownerPriv = PrivateKey11.fromWif(wif);
|
|
6668
6802
|
const ownerAddr = ownerPriv.toPublicKey().toAddress();
|
|
6669
6803
|
const payload = await fetchScopePayload(session_txid);
|
|
6670
6804
|
if (!payload) return { success: false, error: `could not fetch scope tx ${session_txid}` };
|
|
6671
6805
|
const fmt = detectSaveFormat({ wrap_owner: payload.wrap_owner, wrap_self: payload.wrap_self, wrap_version: payload.wrap_version });
|
|
6672
6806
|
let contentKey;
|
|
6673
6807
|
if (fmt === "v3-wallet") {
|
|
6674
|
-
const rv3 = await unwrapForSelfV3(payload.wrap_self, new
|
|
6808
|
+
const rv3 = await unwrapForSelfV3(payload.wrap_self, new CompletedProtoWallet4(ownerPriv), payload.key_id);
|
|
6675
6809
|
if (!rv3.ok) {
|
|
6676
6810
|
return { success: false, error: rv3.reason === "wallet_unavailable" ? "failed to unwrap own v3 content_key: no wallet available" : `failed to unwrap own v3 content_key: ${rv3.reason} (wallet-native saves made by an external wallet can only be shared from the web app)` };
|
|
6677
6811
|
}
|
|
@@ -6764,7 +6898,7 @@ async function indexShareOnBridge(txId, envelope, ownerPriv) {
|
|
|
6764
6898
|
// the envelope stamps ISO; the bridge index demands ms-epoch (putShare validation)
|
|
6765
6899
|
issued_at: typeof envelope.issued_at === "number" ? envelope.issued_at : Date.parse(envelope.issued_at)
|
|
6766
6900
|
};
|
|
6767
|
-
const af = new AuthFetch2(new
|
|
6901
|
+
const af = new AuthFetch2(new CompletedProtoWallet4(ownerPriv));
|
|
6768
6902
|
let lastErr = null;
|
|
6769
6903
|
for (const b of bridges.slice(0, 3)) {
|
|
6770
6904
|
try {
|
|
@@ -7083,7 +7217,7 @@ Commands:
|
|
|
7083
7217
|
}
|
|
7084
7218
|
function printHelp() {
|
|
7085
7219
|
console.log(`
|
|
7086
|
-
Indelible MCP \u2014 Blockchain memory for Claude Code (v4.8.
|
|
7220
|
+
Indelible MCP \u2014 Blockchain memory for Claude Code (v4.8.2)
|
|
7087
7221
|
|
|
7088
7222
|
Setup:
|
|
7089
7223
|
indelible-mcp setup --wif=KEY --pin=PIN Import and encrypt your private key
|
|
@@ -7302,7 +7436,7 @@ function readStdin() {
|
|
|
7302
7436
|
}
|
|
7303
7437
|
var SERVER_INFO = {
|
|
7304
7438
|
name: "indelible",
|
|
7305
|
-
version: "4.8.
|
|
7439
|
+
version: "4.8.2",
|
|
7306
7440
|
description: "Blockchain-backed memory and code storage for Claude Code"
|
|
7307
7441
|
};
|
|
7308
7442
|
var TOOLS = [
|