indelible-mcp 5.7.0 → 5.7.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/CLI_HANDBOOK.md +26 -0
- package/CUSTOMER_AGENT_HANDBOOK.md +9 -0
- package/LICENSE +1 -1
- package/package.json +1 -1
- package/src/index.js +43 -17
package/CLI_HANDBOOK.md
CHANGED
|
@@ -25,6 +25,32 @@ You don't have to memorize any of this. In Claude Code you can just say what you
|
|
|
25
25
|
|
|
26
26
|
Three things worth knowing, once: **your key stays on your machine** (nothing we run ever sees it) · **reading is always free** (saves cost fractions of a cent in Bitcoin fees) · **your stop button beats everything** (pause works even with no wallet at all).
|
|
27
27
|
|
|
28
|
+
## Honest Receipts + the Wallet (5.7.0)
|
|
29
|
+
|
|
30
|
+
**"Committed" now means mined.** A fresh save reports `pending` until a miner buries it in a block
|
|
31
|
+
(usually within about ten minutes), then confirms on its own. Your data still broadcasts in seconds;
|
|
32
|
+
only the word got stricter. No server's acceptance — including ours — is ever reported as
|
|
33
|
+
confirmation anymore.
|
|
34
|
+
|
|
35
|
+
**Double-spends are final the first time the network says so.** If two of your machines ever race
|
|
36
|
+
for the same coin, the losing save is told the truth immediately and rebuilds on fresh coins,
|
|
37
|
+
instead of being retried until something said yes.
|
|
38
|
+
|
|
39
|
+
**The wrong-key guard.** If your config ever holds a key that does not match your account address,
|
|
40
|
+
every save refuses before any money moves and names both addresses, because data written with the
|
|
41
|
+
wrong key can never be read back by your wallet.
|
|
42
|
+
|
|
43
|
+
### `indelible-mcp wallet`
|
|
44
|
+
Shows every coin reservation your wallet is holding: which process holds it, whether that process is
|
|
45
|
+
alive, and what it has locked. If a crashed process left a stuck reservation, free it with
|
|
46
|
+
`indelible-mcp wallet --cancel=<token-prefix>`. It refuses to cancel anything a live process still
|
|
47
|
+
holds, and anything with a signed transaction attached — freeing those is how double-spends happen,
|
|
48
|
+
so it structurally cannot.
|
|
49
|
+
|
|
50
|
+
### Background auto-save
|
|
51
|
+
Runs every 15 minutes by default on every install. Change the pace on the MCP tab at indelible.one —
|
|
52
|
+
your machine picks the new setting up automatically.
|
|
53
|
+
|
|
28
54
|
## Two Pilots (5.2.0)
|
|
29
55
|
|
|
30
56
|
Indelible works with Claude Code, with OpenAI's Codex CLI, or with both at once on the same memory.
|
|
@@ -192,6 +192,15 @@ This fetches the pack and backfills meaning-vectors for your existing history. I
|
|
|
192
192
|
|
|
193
193
|
**`diary_recall`** is the same power scoped to your companion's own history. `scope: "diary"` for saved diary entries, `"duo"` for live Claude-plus-companion rounds, `"all"` for both.
|
|
194
194
|
|
|
195
|
+
### Honest receipts (5.7.0)
|
|
196
|
+
|
|
197
|
+
A save now reports `pending` until a miner buries it in a block, then it becomes `committed` on its
|
|
198
|
+
own. Nothing — not our servers, not a relay — can call your save confirmed anymore. Only the chain
|
|
199
|
+
can. If a save ever loses a race to another machine spending the same coin, you are told the truth
|
|
200
|
+
immediately and the save rebuilds itself on fresh coins. And if your configuration ever holds a key
|
|
201
|
+
that does not belong to your account, saving refuses before any money moves, because data written
|
|
202
|
+
under the wrong key is data your wallet can never read back.
|
|
203
|
+
|
|
195
204
|
### Two pilots on one memory (5.2.0)
|
|
196
205
|
|
|
197
206
|
Your memory is not tied to one AI. Wire OpenAI's Codex CLI to the same install (`~/.codex/config.toml` → `[mcp_servers.indelible]` `command = "indelible-mcp"`) and it reads and writes the same chain as Claude Code. Every save is stamped with its author inside the encrypted record; the Context tab on indelible.one shows `Saved by Claude` or `Saved by Codex` once your record decrypts, and if an index ever claims a different author than your decrypted record proves, the app shows you both values and trusts neither.
|
package/LICENSE
CHANGED
|
@@ -11,7 +11,7 @@ Additional Use Grant: You may make use of the Licensed Work for personal,
|
|
|
11
11
|
commercial blockchain storage, session saving, or
|
|
12
12
|
encrypted vault service without written permission
|
|
13
13
|
from the Licensor.
|
|
14
|
-
Change Date: August
|
|
14
|
+
Change Date: August 14, 2030
|
|
15
15
|
Change License: MIT License
|
|
16
16
|
|
|
17
17
|
Terms
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -3122,7 +3122,12 @@ function appendReceipt(receipt, meta = {}) {
|
|
|
3122
3122
|
// has the IDE shown this entry yet?
|
|
3123
3123
|
};
|
|
3124
3124
|
appendFileSync(LOG, JSON.stringify(entry) + "\n");
|
|
3125
|
-
} catch {
|
|
3125
|
+
} catch (e) {
|
|
3126
|
+
try {
|
|
3127
|
+
process.stderr.write(`[save-log] \u26A0\uFE0F could not record receipt for ${String(receipt.txid).slice(0, 12)}\u2026 (${e.message}) \u2014 the save is on chain, but this receipt is not in the local ledger; reconciliation by content may be needed later
|
|
3128
|
+
`);
|
|
3129
|
+
} catch {
|
|
3130
|
+
}
|
|
3126
3131
|
}
|
|
3127
3132
|
}
|
|
3128
3133
|
var DIR2, LOG;
|
|
@@ -9098,7 +9103,7 @@ function makeHeartbeat(cfg2) {
|
|
|
9098
9103
|
}
|
|
9099
9104
|
return set;
|
|
9100
9105
|
};
|
|
9101
|
-
const
|
|
9106
|
+
const emit2 = async (kind, payload2, parents, entryEpoch) => {
|
|
9102
9107
|
const ikBasis = digest2(DIGEST_DOMAINS.event, canonicalize2({ me, kind, payload: payload2, parents }));
|
|
9103
9108
|
const ev = makeEvent({
|
|
9104
9109
|
event_kind: kind,
|
|
@@ -9148,7 +9153,7 @@ function makeHeartbeat(cfg2) {
|
|
|
9148
9153
|
for (const pe of peerEvents) {
|
|
9149
9154
|
const reply = cfg2.respond?.(pe);
|
|
9150
9155
|
if (reply) {
|
|
9151
|
-
const r = await
|
|
9156
|
+
const r = await emit2(reply.kind, reply.payload, [pe.event_id], epoch);
|
|
9152
9157
|
if (r.published) {
|
|
9153
9158
|
cfg2.onLine?.(`[${me}] \u2192 ${reply.line ?? reply.kind} (answering ${pe.actor.host})`);
|
|
9154
9159
|
reacted = { to: pe.event_id, emitted: r.event_id };
|
|
@@ -9166,7 +9171,7 @@ function makeHeartbeat(cfg2) {
|
|
|
9166
9171
|
if (!reacted) {
|
|
9167
9172
|
const move = cfg2.generate?.();
|
|
9168
9173
|
if (move) {
|
|
9169
|
-
const r = await
|
|
9174
|
+
const r = await emit2(move.kind, move.payload, [], epoch);
|
|
9170
9175
|
if (r.published) {
|
|
9171
9176
|
cfg2.onLine?.(`[${me}] \u270E ${move.line ?? move.kind}`);
|
|
9172
9177
|
generated = r.event_id;
|
|
@@ -11028,14 +11033,18 @@ async function saveFile(filePath, options = {}) {
|
|
|
11028
11033
|
timestamp
|
|
11029
11034
|
});
|
|
11030
11035
|
await saveConfig({ ...config2, file_txids: files });
|
|
11036
|
+
let indexed = false;
|
|
11031
11037
|
try {
|
|
11032
11038
|
const apiUrl = config2.api_url || "https://indelible.one";
|
|
11033
|
-
await fetch(`${apiUrl}/api/files/index`, {
|
|
11039
|
+
const ir = await fetch(`${apiUrl}/api/files/index`, {
|
|
11034
11040
|
method: "POST",
|
|
11035
11041
|
headers: { "Content-Type": "application/json" },
|
|
11036
|
-
body: JSON.stringify({ address: config2.address, txId: masterTxId, filename, path: relativePath, size: fileSize, contentHash: `sha256:${contentHash}`, timestamp })
|
|
11042
|
+
body: JSON.stringify({ address: config2.address, txId: masterTxId, filename, path: relativePath, size: fileSize, contentHash: `sha256:${contentHash}`, timestamp }),
|
|
11043
|
+
signal: AbortSignal.timeout(5e3)
|
|
11037
11044
|
});
|
|
11045
|
+
indexed = !!(ir && ir.ok);
|
|
11038
11046
|
} catch {
|
|
11047
|
+
indexed = false;
|
|
11039
11048
|
}
|
|
11040
11049
|
const chunkCount = encrypted.length <= MAX_CHUNK_SIZE ? 1 : Math.ceil(encrypted.length / MAX_CHUNK_SIZE);
|
|
11041
11050
|
const receipt = buildReceipt(_finalWrite, { txId: masterTxId, fee: _saveFee, txSize: _finalSize });
|
|
@@ -11049,6 +11058,8 @@ async function saveFile(filePath, options = {}) {
|
|
|
11049
11058
|
contentHash: `sha256:${contentHash}`,
|
|
11050
11059
|
chunks: chunkCount,
|
|
11051
11060
|
changeUtxos: finalChangeUtxos,
|
|
11061
|
+
indexed,
|
|
11062
|
+
// QA 94701: file-save receipts now report index state, like session saves already do
|
|
11052
11063
|
receipt,
|
|
11053
11064
|
message: `File "${filename}" saved to blockchain.${chunkCount > 1 ? ` (${chunkCount} chunks)` : ""}
|
|
11054
11065
|
|
|
@@ -14176,7 +14187,7 @@ var err5 = (code, msg) => {
|
|
|
14176
14187
|
return e;
|
|
14177
14188
|
};
|
|
14178
14189
|
var ROLES = ["propose", "attack", "arbitrate"];
|
|
14179
|
-
async function conveneChamber({ scope, seats, task, context = "", provider = "anthropic", model, client, chamber_id, emit = true } = {}) {
|
|
14190
|
+
async function conveneChamber({ scope, seats, task, context = "", provider = "anthropic", model, client, chamber_id, emit: emit2 = true } = {}) {
|
|
14180
14191
|
if (!task || typeof task !== "string") throw err5("CHAMBER_ARGS", "task is required");
|
|
14181
14192
|
if (!Array.isArray(seats) || seats.length !== 3) throw err5("CHAMBER_SEATS", "a chamber seats exactly three: propose, attack, arbitrate");
|
|
14182
14193
|
const byRole = {};
|
|
@@ -14196,7 +14207,7 @@ async function conveneChamber({ scope, seats, task, context = "", provider = "an
|
|
|
14196
14207
|
}
|
|
14197
14208
|
const idSeed = `${task}|${byRole.propose},${byRole.attack},${byRole.arbitrate}`;
|
|
14198
14209
|
const id = chamber_id || `chamber-${Math.abs([...idSeed].reduce((h, c) => h * 31 + c.charCodeAt(0) | 0, 7))}`;
|
|
14199
|
-
const court =
|
|
14210
|
+
const court = emit2 ? beginCourt({ court_id: id, domain: "chamber", mode: "single", label: task.slice(0, 100) }) : null;
|
|
14200
14211
|
const rounds = [];
|
|
14201
14212
|
const run = (name, roundTask, roundContext) => runCustomAgent({ scope, name, task: roundTask, context: roundContext, provider, model, client });
|
|
14202
14213
|
const p = await run(byRole.propose, task, context);
|
|
@@ -15083,6 +15094,11 @@ function runPreToolUseGuard() {
|
|
|
15083
15094
|
}
|
|
15084
15095
|
process.exit(code);
|
|
15085
15096
|
}
|
|
15097
|
+
function emit(result) {
|
|
15098
|
+
console.log(JSON.stringify(result, null, 2));
|
|
15099
|
+
if (result && result.success === false) process.exitCode = 1;
|
|
15100
|
+
return result;
|
|
15101
|
+
}
|
|
15086
15102
|
async function runCli(args2) {
|
|
15087
15103
|
const command = args2[0];
|
|
15088
15104
|
switch (command) {
|
|
@@ -15149,7 +15165,7 @@ async function runCli(args2) {
|
|
|
15149
15165
|
const summaryIdx = args2.indexOf("--summary");
|
|
15150
15166
|
const summary = summaryIdx !== -1 ? args2.slice(summaryIdx + 1).join(" ") : void 0;
|
|
15151
15167
|
const result = await saveSession(CONTEXT_FILE2, summary);
|
|
15152
|
-
|
|
15168
|
+
emit(result);
|
|
15153
15169
|
break;
|
|
15154
15170
|
}
|
|
15155
15171
|
case "load": {
|
|
@@ -15185,20 +15201,22 @@ async function runCli(args2) {
|
|
|
15185
15201
|
const filePath = args2[2];
|
|
15186
15202
|
if (!filePath) {
|
|
15187
15203
|
console.error("Usage: indelible-mcp vault save-file <path>");
|
|
15204
|
+
process.exitCode = 1;
|
|
15188
15205
|
break;
|
|
15189
15206
|
}
|
|
15190
15207
|
const result = await saveFile(filePath);
|
|
15191
|
-
|
|
15208
|
+
emit(result);
|
|
15192
15209
|
} else if (subCmd === "save-project") {
|
|
15193
15210
|
const dirPath = args2[2];
|
|
15194
15211
|
if (!dirPath) {
|
|
15195
15212
|
console.error("Usage: indelible-mcp vault save-project <dir>");
|
|
15213
|
+
process.exitCode = 1;
|
|
15196
15214
|
break;
|
|
15197
15215
|
}
|
|
15198
15216
|
const nameArg = args2.find((a) => a.startsWith("--name="));
|
|
15199
15217
|
const name = nameArg ? nameArg.split("=")[1] : void 0;
|
|
15200
15218
|
const result = await saveProject(dirPath, { name });
|
|
15201
|
-
|
|
15219
|
+
emit(result);
|
|
15202
15220
|
} else if (subCmd === "load-file") {
|
|
15203
15221
|
const txId = args2[2];
|
|
15204
15222
|
if (!txId) {
|
|
@@ -15208,7 +15226,7 @@ async function runCli(args2) {
|
|
|
15208
15226
|
const outArg = args2.find((a) => a.startsWith("--output="));
|
|
15209
15227
|
const outputPath = outArg ? outArg.split("=")[1] : void 0;
|
|
15210
15228
|
const result = await loadFile(txId, { outputPath });
|
|
15211
|
-
|
|
15229
|
+
emit(result);
|
|
15212
15230
|
} else if (subCmd === "load-project") {
|
|
15213
15231
|
const txId = args2[2];
|
|
15214
15232
|
if (!txId) {
|
|
@@ -15218,7 +15236,7 @@ async function runCli(args2) {
|
|
|
15218
15236
|
const outArg = args2.find((a) => a.startsWith("--output-dir="));
|
|
15219
15237
|
const outputDir = outArg ? outArg.split("=")[1] : void 0;
|
|
15220
15238
|
const result = await loadProject(txId, { outputDir });
|
|
15221
|
-
|
|
15239
|
+
emit(result);
|
|
15222
15240
|
} else if (subCmd === "save-style") {
|
|
15223
15241
|
const filePath = args2[2];
|
|
15224
15242
|
const nameArg = args2.find((a) => a.startsWith("--name="));
|
|
@@ -15232,14 +15250,14 @@ async function runCli(args2) {
|
|
|
15232
15250
|
console.error("Usage: indelible-mcp vault save-style <file> [--name=NAME] [--desc=DESC]");
|
|
15233
15251
|
break;
|
|
15234
15252
|
}
|
|
15235
|
-
|
|
15253
|
+
emit(result);
|
|
15236
15254
|
} else if (subCmd === "load-style") {
|
|
15237
15255
|
const txId = args2[2];
|
|
15238
15256
|
const result = await loadStyle(txId);
|
|
15239
15257
|
console.log(JSON.stringify(result, null, 2));
|
|
15240
15258
|
} else if (subCmd === "update-index") {
|
|
15241
15259
|
const result = await updateVaultIndex();
|
|
15242
|
-
|
|
15260
|
+
emit(result);
|
|
15243
15261
|
} else {
|
|
15244
15262
|
console.log(`
|
|
15245
15263
|
Code Vault \u2014 Encrypted code storage on BSV blockchain
|
|
@@ -16114,13 +16132,21 @@ Answer THAT message and nothing else \u2014 the wire also carries unrelated conv
|
|
|
16114
16132
|
drift ledger [--n=20] THE BOOKS: every summoned mind \u2014 when, who, why, how it ended`);
|
|
16115
16133
|
break;
|
|
16116
16134
|
}
|
|
16135
|
+
case "version":
|
|
16136
|
+
case "--version":
|
|
16137
|
+
case "-v":
|
|
16138
|
+
console.log(SERVER_INFO.version);
|
|
16139
|
+
break;
|
|
16117
16140
|
default:
|
|
16141
|
+
if (command) console.error(`\u2717 unknown command: ${command}
|
|
16142
|
+
`);
|
|
16118
16143
|
printHelp();
|
|
16144
|
+
if (command) process.exitCode = 1;
|
|
16119
16145
|
}
|
|
16120
16146
|
}
|
|
16121
16147
|
function printHelp() {
|
|
16122
16148
|
console.log(`
|
|
16123
|
-
Indelible MCP \u2014 Blockchain memory for Claude Code (v5.7.
|
|
16149
|
+
Indelible MCP \u2014 Blockchain memory for Claude Code (v5.7.2)
|
|
16124
16150
|
|
|
16125
16151
|
Setup:
|
|
16126
16152
|
indelible-mcp setup --wif=KEY --pin=PIN Import and encrypt your private key
|
|
@@ -16447,7 +16473,7 @@ function readStdin() {
|
|
|
16447
16473
|
}
|
|
16448
16474
|
var SERVER_INFO = {
|
|
16449
16475
|
name: "indelible",
|
|
16450
|
-
version: "5.7.
|
|
16476
|
+
version: "5.7.2",
|
|
16451
16477
|
description: "Blockchain-backed memory and code storage for Claude Code"
|
|
16452
16478
|
};
|
|
16453
16479
|
var TOOLS = [
|